mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-14 01:27:34 -05:00
* WIP - Adds support for aliasing P25 Phase 2 tones.Playlist editor - adds editor support for alias actions * Playlist editor implementation and integration into application is complete. Adds JavaFX window monitoring to persist window size/location across application runs. Co-authored-by: Denny <denny@denny-desktop>
This commit is contained in:
1
.idea/dictionaries/denny.xml
generated
1
.idea/dictionaries/denny.xml
generated
@@ -23,6 +23,7 @@
|
|||||||
<w>shoutcast</w>
|
<w>shoutcast</w>
|
||||||
<w>streamable</w>
|
<w>streamable</w>
|
||||||
<w>talkgroup</w>
|
<w>talkgroup</w>
|
||||||
|
<w>talkgroups</w>
|
||||||
<w>tgid</w>
|
<w>tgid</w>
|
||||||
<w>ultravox</w>
|
<w>ultravox</w>
|
||||||
<w>wacn</w>
|
<w>wacn</w>
|
||||||
|
|||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_X" default="true" project-jdk-name="14" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_13" default="false" project-jdk-name="14" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
10
.idea/modules.xml
generated
Normal file
10
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/sdr-trunk.iml" filepath="$PROJECT_DIR$/.idea/modules/sdr-trunk.iml" group="sdr-trunk" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/sdr-trunk_main.iml" filepath="$PROJECT_DIR$/.idea/modules/sdr-trunk_main.iml" group="sdr-trunk" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/sdr-trunk_test.iml" filepath="$PROJECT_DIR$/.idea/modules/sdr-trunk_test.iml" group="sdr-trunk" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
10
build.gradle
10
build.gradle
@@ -24,7 +24,7 @@ plugins {
|
|||||||
id 'java'
|
id 'java'
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id 'org.openjfx.javafxplugin' version '0.0.8'
|
id 'org.openjfx.javafxplugin' version '0.0.8'
|
||||||
id 'org.beryx.runtime' version '1.8.0'
|
id 'org.beryx.runtime' version '1.8.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@@ -33,7 +33,7 @@ repositories {
|
|||||||
maven { url "https://jitpack.io" }
|
maven { url "https://jitpack.io" }
|
||||||
}
|
}
|
||||||
|
|
||||||
version = '0.4.0'
|
version = '0.5.0-alpha1'
|
||||||
sourceCompatibility = '13'
|
sourceCompatibility = '13'
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@@ -65,7 +65,7 @@ dependencies {
|
|||||||
implementation 'com.miglayout:miglayout-swing:5.2'
|
implementation 'com.miglayout:miglayout-swing:5.2'
|
||||||
implementation 'com.mpatric:mp3agic:0.9.1'
|
implementation 'com.mpatric:mp3agic:0.9.1'
|
||||||
implementation 'eu.hansolo:charts:1.0.5'
|
implementation 'eu.hansolo:charts:1.0.5'
|
||||||
implementation 'io.github.dsheirer:radio-reference-api:15.1.2'
|
implementation 'io.github.dsheirer:radio-reference-api:15.1.4'
|
||||||
implementation 'javax.usb:usb-api:1.0.2'
|
implementation 'javax.usb:usb-api:1.0.2'
|
||||||
implementation 'net.coderazzi:tablefilter-swing:5.4.0'
|
implementation 'net.coderazzi:tablefilter-swing:5.4.0'
|
||||||
implementation 'org.apache.commons:commons-lang3:3.8.1'
|
implementation 'org.apache.commons:commons-lang3:3.8.1'
|
||||||
@@ -124,7 +124,7 @@ jar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Java Development Kit (JDK) locations. In order to build OS-specific images, these paths must point to the 'bin'
|
* Java Development Kit (JDK) locations. In order to build OS-specific images, these paths must point to the 'bin'
|
||||||
* directory within a JDK for each of the specified architectures. These JDKs are used by the runtime and runtimeZip
|
* directory within a JDK for each of the specified architectures. These JDKs are used by the runtime and runtimeZip
|
||||||
* tasks to produce platform-specific builds. If none of these paths exists, then an image will be created for the
|
* tasks to produce platform-specific builds. If none of these paths exists, then an image will be created for the
|
||||||
* host OS using the installed JDK.
|
* host OS using the installed JDK.
|
||||||
@@ -174,7 +174,7 @@ runtime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
|
options = ['--strip-debug', '--compress', '2', '--no-header-files', '--no-man-pages']
|
||||||
modules = ['java.desktop', 'java.naming', 'jdk.unsupported', 'jdk.unsupported.desktop', 'java.net.http']
|
modules = ['java.desktop', 'java.naming', 'jdk.unsupported', 'jdk.unsupported.desktop', 'java.net.http', 'java.sql']
|
||||||
imageZip = hasTargetJdk ? file("$buildDir/image/sdr-trunk.zip") : file("$buildDir/image/sdr-trunk-" + version + ".zip")
|
imageZip = hasTargetJdk ? file("$buildDir/image/sdr-trunk.zip") : file("$buildDir/image/sdr-trunk-" + version + ".zip")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
131
sdr-trunk.ipr
131
sdr-trunk.ipr
@@ -34,6 +34,8 @@
|
|||||||
<component name="GradleSettings">
|
<component name="GradleSettings">
|
||||||
<option name="linkedExternalProjectsSettings">
|
<option name="linkedExternalProjectsSettings">
|
||||||
<GradleProjectSettings>
|
<GradleProjectSettings>
|
||||||
|
<option name="delegatedBuild" value="false" />
|
||||||
|
<option name="testRunner" value="PLATFORM" />
|
||||||
<option name="distributionType" value="WRAPPED" />
|
<option name="distributionType" value="WRAPPED" />
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||||
<option name="gradleHome" value="$USER_HOME$/gradle/gradle-2.12" />
|
<option name="gradleHome" value="$USER_HOME$/gradle/gradle-2.12" />
|
||||||
@@ -199,9 +201,36 @@
|
|||||||
<module fileurl="file://$PROJECT_DIR$/sdr-trunk_test.iml" filepath="$PROJECT_DIR$/sdr-trunk_test.iml" group="sdr-trunk" />
|
<module fileurl="file://$PROJECT_DIR$/sdr-trunk_test.iml" filepath="$PROJECT_DIR$/sdr-trunk_test.iml" group="sdr-trunk" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="13" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
|
<component name="RemoteRepositoriesConfiguration">
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="central" />
|
||||||
|
<option name="name" value="Maven Central repository" />
|
||||||
|
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="jboss.community" />
|
||||||
|
<option name="name" value="JBoss Community repository" />
|
||||||
|
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="MavenRepo" />
|
||||||
|
<option name="name" value="MavenRepo" />
|
||||||
|
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="BintrayJCenter" />
|
||||||
|
<option name="name" value="BintrayJCenter" />
|
||||||
|
<option name="url" value="https://jcenter.bintray.com/" />
|
||||||
|
</remote-repository>
|
||||||
|
<remote-repository>
|
||||||
|
<option name="id" value="maven" />
|
||||||
|
<option name="name" value="maven" />
|
||||||
|
<option name="url" value="https://jitpack.io" />
|
||||||
|
</remote-repository>
|
||||||
|
</component>
|
||||||
<component name="SvnBranchConfigurationManager">
|
<component name="SvnBranchConfigurationManager">
|
||||||
<option name="mySupportsUserInfoFilter" value="true" />
|
<option name="mySupportsUserInfoFilter" value="true" />
|
||||||
</component>
|
</component>
|
||||||
@@ -309,6 +338,22 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.fazecast/jSerialComm/2.5.0/b9e6222384a17cb10474b7f25768edf4b742ec16/jSerialComm-2.5.0-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.fazecast/jSerialComm/2.5.0/b9e6222384a17cb10474b7f25768edf4b742ec16/jSerialComm-2.5.0-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
|
<library name="Gradle: com.github.dnault:libresample4j:master">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.dnault/libresample4j/master/188fc23592420c3848916d34e1df327d45e5ccd3/libresample4j-master.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.dnault/libresample4j/master/169939a76de61aee15dc6a1b230569e82d115bb7/libresample4j-master-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
<library name="Gradle: com.github.DSheirer.jmbe:jmbe-api:1.0.0">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.DSheirer.jmbe/jmbe-api/1.0.0/b914e8f914b7b3d535d1e7bbbbb09ddd37bef726/jmbe-api-1.0.0.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
<library name="Gradle: com.github.jiconfont:jiconfont-font_awesome:4.7.0.1">
|
<library name="Gradle: com.github.jiconfont:jiconfont-font_awesome:4.7.0.1">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.jiconfont/jiconfont-font_awesome/4.7.0.1/121d019023f631af04a1357e637dd05a2cc91f7b/jiconfont-font_awesome-4.7.0.1.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.jiconfont/jiconfont-font_awesome/4.7.0.1/121d019023f631af04a1357e637dd05a2cc91f7b/jiconfont-font_awesome-4.7.0.1.jar!/" />
|
||||||
@@ -353,6 +398,13 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.jiconfont/jiconfont/1.0.0/e79316fba9458423ce944fba6da101262549464/jiconfont-1.0.0-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.jiconfont/jiconfont/1.0.0/e79316fba9458423ce944fba6da101262549464/jiconfont-1.0.0-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
|
<library name="Gradle: com.github.nwaldispuehl:java-lame:v3.98.4">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.nwaldispuehl/java-lame/v3.98.4/b4917736b83335704dc5af44671ea27a339cc496/java-lame-v3.98.4.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC />
|
||||||
|
<SOURCES />
|
||||||
|
</library>
|
||||||
<library name="Gradle: com.github.wendykierp:JTransforms:3.1">
|
<library name="Gradle: com.github.wendykierp:JTransforms:3.1">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.wendykierp/JTransforms/3.1/f1f6d3c9c9bc04f848e38bdb77dea01e8764a01f/JTransforms-3.1.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.github.wendykierp/JTransforms/3.1/f1f6d3c9c9bc04f848e38bdb77dea01e8764a01f/JTransforms-3.1.jar!/" />
|
||||||
@@ -417,13 +469,13 @@
|
|||||||
</library>
|
</library>
|
||||||
<library name="Gradle: com.google.j2objc:j2objc-annotations:1.1">
|
<library name="Gradle: com.google.j2objc:j2objc-annotations:1.1">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/976d8d30bebc251db406f2bdb3eb01962b5685b3/j2objc-annotations-1.1.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/ed28ded51a8b1c6b112568def5f4b455e6809019/j2objc-annotations-1.1.jar!/" />
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC>
|
<JAVADOC>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/2e1e0c8db5be95ec85d19d456186f8989ea263fa/j2objc-annotations-1.1-javadoc.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/5d415cbe46a293283658196abdb9e6d06dc68ccf/j2objc-annotations-1.1-javadoc.jar!/" />
|
||||||
</JAVADOC>
|
</JAVADOC>
|
||||||
<SOURCES>
|
<SOURCES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/dcd31de68a90e41e336f6b7afce0d39285c433d7/j2objc-annotations-1.1-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/com.google.j2objc/j2objc-annotations/1.1/1efdf5b737b02f9b72ebdec4f72c37ec411302ff/j2objc-annotations-1.1-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
<library name="Gradle: com.jidesoft:jide-oss:3.6.18">
|
<library name="Gradle: com.jidesoft:jide-oss:3.6.18">
|
||||||
@@ -481,15 +533,15 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/eu.hansolo/charts/1.0.5/aa26011a2c525ddf86cb92ed23558b18c0174fa4/charts-1.0.5-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/eu.hansolo/charts/1.0.5/aa26011a2c525ddf86cb92ed23558b18c0174fa4/charts-1.0.5-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
<library name="Gradle: io.github.dsheirer:radio-reference-api:15.0.1">
|
<library name="Gradle: io.github.dsheirer:radio-reference-api:15.1.2">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.github.dsheirer/radio-reference-api/15.0.1/8af16506c26025517f0bc971ba35485e96130c9a/radio-reference-api-15.0.1.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.github.dsheirer/radio-reference-api/15.1.2/5af53224d83af52ba68bd690c8101e5fe2a492ff/radio-reference-api-15.1.2.jar!/" />
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC>
|
<JAVADOC>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.github.dsheirer/radio-reference-api/15.0.1/219528429b3ed73f285a8c2c4ded40d8eae61fc0/radio-reference-api-15.0.1-javadoc.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.github.dsheirer/radio-reference-api/15.1.2/75cfe3736f421290f6796d943c1a4b05b32d8526/radio-reference-api-15.1.2-javadoc.jar!/" />
|
||||||
</JAVADOC>
|
</JAVADOC>
|
||||||
<SOURCES>
|
<SOURCES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.github.dsheirer/radio-reference-api/15.0.1/b699a9821030b54fbb7f472f97fcc634afb114fb/radio-reference-api-15.0.1-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/io.github.dsheirer/radio-reference-api/15.1.2/250df667ec2cea0219a9951d3b2144d87d0cf755/radio-reference-api-15.1.2-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
<library name="Gradle: javax.usb:usb-api:1.0.2">
|
<library name="Gradle: javax.usb:usb-api:1.0.2">
|
||||||
@@ -536,15 +588,15 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.8.1/e9748d7783594da3735ad9724390a10e7cebc01d/commons-lang3-3.8.1-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-lang3/3.8.1/e9748d7783594da3735ad9724390a10e7cebc01d/commons-lang3-3.8.1-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
<library name="Gradle: org.apache.commons:commons-math3:3.5">
|
<library name="Gradle: org.apache.commons:commons-math3:3.6.1">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.5/13af68e9a11576953f5c4b09436f8207be9d3a27/commons-math3-3.5.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.6.1/e4ba98f1d4b3c80ec46392f25e094a6a2e58fcbf/commons-math3-3.6.1.jar!/" />
|
||||||
</CLASSES>
|
</CLASSES>
|
||||||
<JAVADOC>
|
<JAVADOC>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.5/e6106a9927c5ee66d0e647ad116af26c9b6b5f06/commons-math3-3.5-javadoc.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.6.1/2e894b7acae199b5dff08bb596334594b5f23c28/commons-math3-3.6.1-javadoc.jar!/" />
|
||||||
</JAVADOC>
|
</JAVADOC>
|
||||||
<SOURCES>
|
<SOURCES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.5/1d3f412d28c8bff0e8f048240b08bcd21cfa432e/commons-math3-3.5-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.apache.commons/commons-math3/3.6.1/8fab23986ea8886af34818daf32a718e81dc98ba/commons-math3-3.6.1-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
<library name="Gradle: org.apache.mina:mina-core:2.0.19">
|
<library name="Gradle: org.apache.mina:mina-core:2.0.19">
|
||||||
@@ -613,6 +665,17 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/3.1.4/b40604d61c01cc081a4a7bdfc562aa9847ee8857/stax2-api-3.1.4-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.codehaus.woodstox/stax2-api/3.1.4/b40604d61c01cc081a4a7bdfc562aa9847ee8857/stax2-api-3.1.4-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
|
<library name="Gradle: org.controlsfx:controlsfx:11.0.1">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.controlsfx/controlsfx/11.0.1/66df6f3526734d37226ea36cc32940083e6fb697/controlsfx-11.0.1.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.controlsfx/controlsfx/11.0.1/79c5c32f926c8315a344a04eafa8dd250b545927/controlsfx-11.0.1-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.controlsfx/controlsfx/11.0.1/5d8b9a51a5b463f583e114e95fdecc0071564a0b/controlsfx-11.0.1-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
<library name="Gradle: org.hamcrest:hamcrest-core:1.3">
|
<library name="Gradle: org.hamcrest:hamcrest-core:1.3">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.hamcrest/hamcrest-core/1.3/42a25dc3219429f0e5d060061f71acb49bf010a0/hamcrest-core-1.3.jar!/" />
|
||||||
@@ -668,6 +731,17 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-base/11.0.2/c082cdf645f9833408dcd960bf68344c9384f569/javafx-base-11.0.2-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-base/11.0.2/c082cdf645f9833408dcd960bf68344c9384f569/javafx-base-11.0.2-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
|
<library name="Gradle: org.openjfx:javafx-controls:11.0.2">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-controls/11.0.2/4ab633cf1eea60f76e2ae9905aedac862da88b08/javafx-controls-11.0.2.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-controls/11.0.2/baa088249ee757119688e78d9c3a256928189902/javafx-controls-11.0.2-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-controls/11.0.2/1535a8b57f01a712405a739a0d69e09ab99dbb6b/javafx-controls-11.0.2-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
<library name="Gradle: org.openjfx:javafx-controls:linux:11.0.2">
|
<library name="Gradle: org.openjfx:javafx-controls:linux:11.0.2">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-controls/11.0.2/5f6929050a744aab39ebfc1e8e5dd03bcd2ad47b/javafx-controls-11.0.2-linux.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-controls/11.0.2/5f6929050a744aab39ebfc1e8e5dd03bcd2ad47b/javafx-controls-11.0.2-linux.jar!/" />
|
||||||
@@ -745,6 +819,28 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-graphics/11.0.2/15eadef01f327a851a6d3af0ac89d56292076b13/javafx-graphics-11.0.2-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-graphics/11.0.2/15eadef01f327a851a6d3af0ac89d56292076b13/javafx-graphics-11.0.2-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
|
<library name="Gradle: org.openjfx:javafx-media:11.0.2">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-media/11.0.2/30b3246c67f308de4d7aefbf99acef8d1dce32ad/javafx-media-11.0.2.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-media/11.0.2/20c892c5aa52ce3d87e3c37c9f60be46e328e342/javafx-media-11.0.2-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-media/11.0.2/b189a6ab9f7abdd2ede840e5a90b7002c521f370/javafx-media-11.0.2-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
|
<library name="Gradle: org.openjfx:javafx-media:linux:11.0.2">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-media/11.0.2/8bc5daaa19f2ff103cd85f751ad021eb71ba7db7/javafx-media-11.0.2-linux.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-media/11.0.2/20c892c5aa52ce3d87e3c37c9f60be46e328e342/javafx-media-11.0.2-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-media/11.0.2/b189a6ab9f7abdd2ede840e5a90b7002c521f370/javafx-media-11.0.2-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
<library name="Gradle: org.openjfx:javafx-swing:linux:11.0.2">
|
<library name="Gradle: org.openjfx:javafx-swing:linux:11.0.2">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-swing/11.0.2/cb57db3e5bd1e2b62b17c8a504858bfc26fa54b1/javafx-swing-11.0.2-linux.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-swing/11.0.2/cb57db3e5bd1e2b62b17c8a504858bfc26fa54b1/javafx-swing-11.0.2-linux.jar!/" />
|
||||||
@@ -778,6 +874,17 @@
|
|||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-swing/11.0.2/bcc8c0a402ff01a89a50888c9dc26824a9f3f2cc/javafx-swing-11.0.2-sources.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-swing/11.0.2/bcc8c0a402ff01a89a50888c9dc26824a9f3f2cc/javafx-swing-11.0.2-sources.jar!/" />
|
||||||
</SOURCES>
|
</SOURCES>
|
||||||
</library>
|
</library>
|
||||||
|
<library name="Gradle: org.openjfx:javafx-web:linux:11.0.2">
|
||||||
|
<CLASSES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-web/11.0.2/49ca03e2fd58cbb0ad94f6a6bd11e0c043e541a7/javafx-web-11.0.2-linux.jar!/" />
|
||||||
|
</CLASSES>
|
||||||
|
<JAVADOC>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-web/11.0.2/851a1c3ecb65f69d69e25cb63958b9a607f665f2/javafx-web-11.0.2-javadoc.jar!/" />
|
||||||
|
</JAVADOC>
|
||||||
|
<SOURCES>
|
||||||
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.openjfx/javafx-web/11.0.2/b33e1bfa75ebf5a6816525a4c77d2a8aea0915c4/javafx-web-11.0.2-sources.jar!/" />
|
||||||
|
</SOURCES>
|
||||||
|
</library>
|
||||||
<library name="Gradle: org.slf4j:slf4j-api:1.7.25">
|
<library name="Gradle: org.slf4j:slf4j-api:1.7.25">
|
||||||
<CLASSES>
|
<CLASSES>
|
||||||
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.25/da76ca59f6a57ee3102f8f9bd9cee742973efa8a/slf4j-api-1.7.25.jar!/" />
|
<root url="jar://$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.slf4j/slf4j-api/1.7.25/da76ca59f6a57ee3102f8f9bd9cee742973efa8a/slf4j-api-1.7.25.jar!/" />
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
*/
|
||||||
package io.github.dsheirer.alias;
|
package io.github.dsheirer.alias;
|
||||||
|
|
||||||
@@ -28,161 +30,465 @@ import io.github.dsheirer.alias.id.AliasIDType;
|
|||||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
||||||
import io.github.dsheirer.alias.id.priority.Priority;
|
import io.github.dsheirer.alias.id.priority.Priority;
|
||||||
import io.github.dsheirer.alias.id.record.Record;
|
import io.github.dsheirer.alias.id.record.Record;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.binding.BooleanBinding;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.IntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.transformation.FilteredList;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias provides an aliasing (e.g. name, color, etc) container that is linked to multiple alias identifiers and
|
||||||
|
* provides a corresponding set of actions related to the alias.
|
||||||
|
*/
|
||||||
@JacksonXmlRootElement(localName = "alias")
|
@JacksonXmlRootElement(localName = "alias")
|
||||||
public class Alias
|
public class Alias
|
||||||
{
|
{
|
||||||
private String mList;
|
private final static Logger mLog = LoggerFactory.getLogger(Alias.class);
|
||||||
private String mGroup;
|
|
||||||
private String mName;
|
|
||||||
private int mColor;
|
|
||||||
private String mIconName;
|
|
||||||
private List<AliasID> mAliasIDs = new ArrayList<AliasID>();
|
|
||||||
private List<AliasAction> mAliasActions = new ArrayList<AliasAction>();
|
|
||||||
|
|
||||||
public Alias()
|
private BooleanProperty mRecordable = new SimpleBooleanProperty();
|
||||||
{
|
private BooleanProperty mStreamable = new SimpleBooleanProperty();
|
||||||
}
|
private BooleanProperty mOverlap = new SimpleBooleanProperty();
|
||||||
|
private IntegerProperty mColor = new SimpleIntegerProperty();
|
||||||
|
private IntegerProperty mPriority = new SimpleIntegerProperty(Priority.DEFAULT_PRIORITY);
|
||||||
|
private IntegerProperty mNonAudioIdentifierCount = new SimpleIntegerProperty();
|
||||||
|
private StringProperty mAliasListName = new SimpleStringProperty();
|
||||||
|
private StringProperty mGroup = new SimpleStringProperty();
|
||||||
|
private StringProperty mIconName = new SimpleStringProperty();
|
||||||
|
private StringProperty mName = new SimpleStringProperty();
|
||||||
|
private ObservableList<AliasID> mAliasIDs = FXCollections.observableArrayList();
|
||||||
|
private ObservableList<AliasAction> mAliasActions = FXCollections.observableArrayList();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance and sets the specified name.
|
||||||
|
* @param name for the alias
|
||||||
|
*/
|
||||||
public Alias(String name)
|
public Alias(String name)
|
||||||
{
|
{
|
||||||
mName = name;
|
mName.set(name);
|
||||||
|
|
||||||
|
//Bind the non-audio identifier count property to the size of a filtered list of alias identifiers
|
||||||
|
mNonAudioIdentifierCount.bind(Bindings.size(new FilteredList<>(mAliasIDs, aliasID -> {
|
||||||
|
return aliasID != null && !aliasID.isAudioIdentifier();
|
||||||
|
})));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance
|
||||||
|
*/
|
||||||
|
public Alias()
|
||||||
|
{
|
||||||
|
this(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Count of non-audio identifiers for this alias
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public IntegerProperty nonAudioIdentifierCountProperty()
|
||||||
|
{
|
||||||
|
return mNonAudioIdentifierCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Audio playback priority
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public IntegerProperty priorityProperty()
|
||||||
|
{
|
||||||
|
return mPriority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if one or more of the identifiers for this alias overlap with identifiers from another alias
|
||||||
|
* within the same alias list.
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public BooleanProperty overlapProperty()
|
||||||
|
{
|
||||||
|
return mOverlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recordable property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public BooleanProperty recordableProperty()
|
||||||
|
{
|
||||||
|
return mRecordable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Streamable property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public BooleanProperty streamableProperty()
|
||||||
|
{
|
||||||
|
return mStreamable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias list name property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public StringProperty aliasListNameProperty()
|
||||||
|
{
|
||||||
|
return mAliasListName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Group property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public StringProperty groupProperty()
|
||||||
|
{
|
||||||
|
return mGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias name property
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public StringProperty nameProperty()
|
||||||
|
{
|
||||||
|
return mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias color value property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public IntegerProperty colorProperty()
|
||||||
|
{
|
||||||
|
return mColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon name property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public StringProperty iconNameProperty()
|
||||||
|
{
|
||||||
|
return mIconName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias identifiers list property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public ObservableList<AliasID> aliasIds()
|
||||||
|
{
|
||||||
|
return mAliasIDs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias actions list property
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public ObservableList<AliasAction> aliasActions()
|
||||||
|
{
|
||||||
|
return mAliasActions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses name value for string representation
|
||||||
|
*/
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return getName();
|
return getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias name
|
||||||
|
*/
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "name")
|
@JacksonXmlProperty(isAttribute = true, localName = "name")
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return mName;
|
return mName.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String name)
|
public void setName(String name)
|
||||||
{
|
{
|
||||||
mName = name;
|
mName.set(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias list name for the alias list that this alias belongs to
|
||||||
|
*/
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "list")
|
@JacksonXmlProperty(isAttribute = true, localName = "list")
|
||||||
public String getList()
|
public String getAliasListName()
|
||||||
{
|
{
|
||||||
return mList;
|
return mAliasListName.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setList(String list)
|
public void setAliasListName(String aliasListName)
|
||||||
{
|
{
|
||||||
mList = list;
|
mAliasListName.set(aliasListName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean matchesAliasList(String aliasList)
|
||||||
|
{
|
||||||
|
boolean isEmptyArgument = aliasList == null || aliasList.isEmpty() || aliasList.contentEquals(AliasModel.NO_ALIAS_LIST);
|
||||||
|
boolean isEmptyThis = getAliasListName() == null || getAliasListName().isEmpty();
|
||||||
|
|
||||||
|
if(isEmptyArgument && isEmptyThis)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(!isEmptyArgument && !isEmptyThis && aliasList.contentEquals(getAliasListName()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this alias has a specified alias list name
|
||||||
|
*/
|
||||||
public boolean hasList()
|
public boolean hasList()
|
||||||
{
|
{
|
||||||
return mList != null;
|
return mAliasListName.get() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grouping tag for this alias.
|
||||||
|
*/
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "group")
|
@JacksonXmlProperty(isAttribute = true, localName = "group")
|
||||||
public String getGroup()
|
public String getGroup()
|
||||||
{
|
{
|
||||||
return mGroup;
|
return mGroup.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGroup(String group)
|
public void setGroup(String group)
|
||||||
{
|
{
|
||||||
mGroup = group;
|
mGroup.set(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this alias has a grouping tag
|
||||||
|
*/
|
||||||
public boolean hasGroup()
|
public boolean hasGroup()
|
||||||
{
|
{
|
||||||
return mGroup != null;
|
return mGroup.get() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Color (RGBA) value to use for this alias
|
||||||
|
*/
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "color")
|
@JacksonXmlProperty(isAttribute = true, localName = "color")
|
||||||
public int getColor()
|
public int getColor()
|
||||||
{
|
{
|
||||||
return mColor;
|
return mColor.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
public String getColorHex()
|
||||||
|
{
|
||||||
|
return String.format("#%06X", (0xFFFFFF & mColor.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setColor(int color)
|
public void setColor(int color)
|
||||||
{
|
{
|
||||||
mColor = color;
|
mColor.set(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display color for this alias.
|
||||||
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public Color getDisplayColor()
|
public Color getDisplayColor()
|
||||||
{
|
{
|
||||||
return new Color(getColor());
|
return new Color(getColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icon name of the icon to use for this alias.
|
||||||
|
*/
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "iconName")
|
@JacksonXmlProperty(isAttribute = true, localName = "iconName")
|
||||||
public String getIconName()
|
public String getIconName()
|
||||||
{
|
{
|
||||||
return mIconName;
|
return mIconName.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIconName(String iconName)
|
public void setIconName(String iconName)
|
||||||
{
|
{
|
||||||
mIconName = iconName;
|
mIconName.set(iconName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of alias identifiers for this alias.
|
||||||
|
*/
|
||||||
@JacksonXmlProperty(isAttribute = false, localName = "id")
|
@JacksonXmlProperty(isAttribute = false, localName = "id")
|
||||||
public List<AliasID> getId()
|
public List<AliasID> getAliasIdentifiers()
|
||||||
{
|
{
|
||||||
return mAliasIDs;
|
return mAliasIDs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setId(ArrayList<AliasID> id)
|
public void setAliasIdentifiers(List<AliasID> id)
|
||||||
{
|
{
|
||||||
mAliasIDs = id;
|
mAliasIDs.clear();
|
||||||
|
|
||||||
|
for(AliasID aliasID : id)
|
||||||
|
{
|
||||||
|
addAliasID(aliasID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an alias identifier to this alias and updates the recordable and streamable attributes.
|
||||||
|
*/
|
||||||
public void addAliasID(AliasID id)
|
public void addAliasID(AliasID id)
|
||||||
{
|
{
|
||||||
mAliasIDs.add(id);
|
mAliasIDs.add(id);
|
||||||
|
validate();
|
||||||
|
updateOverlapBinding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an alias identifier from this alias and updates the recordable and streamable attributes.
|
||||||
|
*/
|
||||||
public void removeAliasID(AliasID id)
|
public void removeAliasID(AliasID id)
|
||||||
{
|
{
|
||||||
mAliasIDs.remove(id);
|
if(id != null)
|
||||||
|
{
|
||||||
|
mAliasIDs.remove(id);
|
||||||
|
validate();
|
||||||
|
updateOverlapBinding();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of alias actions associated with this alias.
|
||||||
|
*/
|
||||||
@JacksonXmlProperty(isAttribute = false, localName = "action")
|
@JacksonXmlProperty(isAttribute = false, localName = "action")
|
||||||
public List<AliasAction> getAction()
|
public List<AliasAction> getAliasActions()
|
||||||
{
|
{
|
||||||
return mAliasActions;
|
return mAliasActions;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAction(List<AliasAction> actions)
|
public void setAliasActions(List<AliasAction> actions)
|
||||||
{
|
{
|
||||||
mAliasActions = actions;
|
mAliasActions.setAll(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the specified alias action to this alias
|
||||||
|
*/
|
||||||
public void addAliasAction(AliasAction action)
|
public void addAliasAction(AliasAction action)
|
||||||
{
|
{
|
||||||
mAliasActions.add(action);
|
mAliasActions.add(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes the specified alias action from this alias
|
||||||
|
*/
|
||||||
public void removeAliasAction(AliasAction action)
|
public void removeAliasAction(AliasAction action)
|
||||||
{
|
{
|
||||||
mAliasActions.remove(action);
|
mAliasActions.remove(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this alias has any associated
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public boolean hasActions()
|
public boolean hasActions()
|
||||||
{
|
{
|
||||||
return !mAliasActions.isEmpty();
|
return !mAliasActions.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the playback priority this alias
|
||||||
|
*/
|
||||||
|
private void updatePriority()
|
||||||
|
{
|
||||||
|
for(AliasID aliasID: mAliasIDs)
|
||||||
|
{
|
||||||
|
if(aliasID instanceof Priority)
|
||||||
|
{
|
||||||
|
mPriority.set(((Priority)aliasID).getPriority());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mPriority.set(Priority.DEFAULT_PRIORITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateOverlapBinding()
|
||||||
|
{
|
||||||
|
mOverlap.unbind();
|
||||||
|
|
||||||
|
BooleanBinding binding = new SimpleBooleanProperty(true).not();
|
||||||
|
|
||||||
|
for(AliasID aliasID: mAliasIDs)
|
||||||
|
{
|
||||||
|
binding = binding.or(aliasID.overlapProperty());
|
||||||
|
}
|
||||||
|
|
||||||
|
mOverlap.bind(binding);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the recordable status for this alias
|
||||||
|
*/
|
||||||
|
private void updateRecordable()
|
||||||
|
{
|
||||||
|
for(AliasID aliasID: mAliasIDs)
|
||||||
|
{
|
||||||
|
if(aliasID instanceof Record)
|
||||||
|
{
|
||||||
|
mRecordable.set(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mRecordable.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the streamable status for this alias
|
||||||
|
*/
|
||||||
|
private void updateStreamable()
|
||||||
|
{
|
||||||
|
for(AliasID aliasID: mAliasIDs)
|
||||||
|
{
|
||||||
|
if(aliasID instanceof BroadcastChannel)
|
||||||
|
{
|
||||||
|
mStreamable.set(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mStreamable.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform any validation/cleanup actions on this alias.
|
* Perform any validation/cleanup actions on this alias.
|
||||||
*/
|
*/
|
||||||
public void validate()
|
public void validate()
|
||||||
{
|
{
|
||||||
|
updatePriority();
|
||||||
|
updateRecordable();
|
||||||
|
updateStreamable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,22 +526,23 @@ public class Alias
|
|||||||
*/
|
*/
|
||||||
public void setCallPriority(int priority)
|
public void setCallPriority(int priority)
|
||||||
{
|
{
|
||||||
if(priority == Priority.DO_NOT_MONITOR ||
|
AliasID priorityID = null;
|
||||||
(Priority.MIN_PRIORITY <= priority && priority <= Priority.MAX_PRIORITY))
|
|
||||||
{
|
|
||||||
for(AliasID id : mAliasIDs)
|
|
||||||
{
|
|
||||||
if(id.getType() == AliasIDType.PRIORITY)
|
|
||||||
{
|
|
||||||
((Priority)id).setPriority(priority);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//If we don't find a priority id, create one
|
for(AliasID aliasID: mAliasIDs)
|
||||||
Priority p = new Priority();
|
{
|
||||||
p.setPriority(priority);
|
if(aliasID instanceof Priority)
|
||||||
addAliasID(p);
|
{
|
||||||
|
priorityID = aliasID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAliasID(priorityID);
|
||||||
|
|
||||||
|
//Don't add a priority alias id if the priority is MAX_PRIORITY or DEFAULT_PRIORITY since the getCallPriority()
|
||||||
|
//will return that as the default value
|
||||||
|
if(priority == Priority.DO_NOT_MONITOR || (Priority.MIN_PRIORITY <= priority && priority < Priority.MAX_PRIORITY))
|
||||||
|
{
|
||||||
|
addAliasID(new Priority(priority));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -245,15 +552,7 @@ public class Alias
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isRecordable()
|
public boolean isRecordable()
|
||||||
{
|
{
|
||||||
for(AliasID id : getId())
|
return mRecordable.get();
|
||||||
{
|
|
||||||
if(id.getType() == AliasIDType.RECORD)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -261,36 +560,22 @@ public class Alias
|
|||||||
*/
|
*/
|
||||||
public void setRecordable(boolean recordable)
|
public void setRecordable(boolean recordable)
|
||||||
{
|
{
|
||||||
|
AliasID recordID = null;
|
||||||
|
|
||||||
|
for(AliasID aliasID: mAliasIDs)
|
||||||
|
{
|
||||||
|
if(aliasID instanceof Record)
|
||||||
|
{
|
||||||
|
recordID = aliasID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeAliasID(recordID);
|
||||||
|
|
||||||
if(recordable)
|
if(recordable)
|
||||||
{
|
{
|
||||||
for(AliasID id : getId())
|
|
||||||
{
|
|
||||||
if(id.getType() == AliasIDType.RECORD)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addAliasID(new Record());
|
addAliasID(new Record());
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
AliasID toRemove = null;
|
|
||||||
|
|
||||||
for(AliasID id : getId())
|
|
||||||
{
|
|
||||||
if(id.getType() == AliasIDType.RECORD)
|
|
||||||
{
|
|
||||||
toRemove = id;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(toRemove != null)
|
|
||||||
{
|
|
||||||
removeAliasID(toRemove);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -299,15 +584,7 @@ public class Alias
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isStreamable()
|
public boolean isStreamable()
|
||||||
{
|
{
|
||||||
for(AliasID id : getId())
|
return mStreamable.get();
|
||||||
{
|
|
||||||
if(id.getType() == AliasIDType.BROADCAST_CHANNEL)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -318,7 +595,7 @@ public class Alias
|
|||||||
{
|
{
|
||||||
Set<BroadcastChannel> broadcastChannels = new TreeSet<>();
|
Set<BroadcastChannel> broadcastChannels = new TreeSet<>();
|
||||||
|
|
||||||
for(AliasID id : getId())
|
for(AliasID id : getAliasIdentifiers())
|
||||||
{
|
{
|
||||||
if(id.getType() == AliasIDType.BROADCAST_CHANNEL)
|
if(id.getType() == AliasIDType.BROADCAST_CHANNEL)
|
||||||
{
|
{
|
||||||
@@ -339,7 +616,7 @@ public class Alias
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(AliasID id : getId())
|
for(AliasID id : getAliasIdentifiers())
|
||||||
{
|
{
|
||||||
if(id.getType() == AliasIDType.BROADCAST_CHANNEL &&
|
if(id.getType() == AliasIDType.BROADCAST_CHANNEL &&
|
||||||
((BroadcastChannel)id).getChannelName().contentEquals(channel))
|
((BroadcastChannel)id).getChannelName().contentEquals(channel))
|
||||||
@@ -350,4 +627,85 @@ public class Alias
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes any broadcast channel(s) that match the argument
|
||||||
|
*/
|
||||||
|
public void removeBroadcastChannel(String channel)
|
||||||
|
{
|
||||||
|
if(channel == null || channel.isEmpty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<AliasID> toRemove = new ArrayList<>();
|
||||||
|
|
||||||
|
for(AliasID aliasID: getAliasIdentifiers())
|
||||||
|
{
|
||||||
|
if(aliasID instanceof BroadcastChannel &&
|
||||||
|
((BroadcastChannel)aliasID).getChannelName().contentEquals(channel))
|
||||||
|
{
|
||||||
|
toRemove.add(aliasID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(AliasID aliasID: toRemove)
|
||||||
|
{
|
||||||
|
removeAliasID(aliasID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes (clears) all broadcast channels from this alias
|
||||||
|
*/
|
||||||
|
public void removeAllBroadcastChannels()
|
||||||
|
{
|
||||||
|
List<AliasID> toRemove = new ArrayList<>();
|
||||||
|
for(AliasID aliasID: mAliasIDs)
|
||||||
|
{
|
||||||
|
if(aliasID instanceof BroadcastChannel)
|
||||||
|
{
|
||||||
|
toRemove.add(aliasID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(AliasID aliasID: toRemove)
|
||||||
|
{
|
||||||
|
removeAliasID(aliasID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all non audio identifiers to prepare for replacing them from an editor.
|
||||||
|
*/
|
||||||
|
public void removeNonAudioIdentifiers()
|
||||||
|
{
|
||||||
|
Iterator<AliasID> it = mAliasIDs.iterator();
|
||||||
|
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
if(!it.next().isAudioIdentifier())
|
||||||
|
{
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all alias actions from this alias
|
||||||
|
*/
|
||||||
|
public void removeAllActions()
|
||||||
|
{
|
||||||
|
mAliasActions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
|
||||||
|
*/
|
||||||
|
public static Callback<Alias,Observable[]> extractor()
|
||||||
|
{
|
||||||
|
return (Alias a) -> new Observable[] {a.recordableProperty(), a.streamableProperty(), a.colorProperty(),
|
||||||
|
a.aliasListNameProperty(), a.groupProperty(), a.iconNameProperty(), a.nameProperty(), a.aliasIds(),
|
||||||
|
a.aliasActions(), a.nonAudioIdentifierCountProperty(), a.overlapProperty()};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,381 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
package io.github.dsheirer.alias;
|
|
||||||
|
|
||||||
import com.jidesoft.swing.JideSplitPane;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
|
||||||
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
|
|
||||||
import net.coderazzi.filters.gui.AutoChoices;
|
|
||||||
import net.coderazzi.filters.gui.TableFilterHeader;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
import javax.swing.table.DefaultTableCellRenderer;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AliasController extends JPanel implements ActionListener, ListSelectionListener
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String TABLE_PREFERENCE_KEY = "alias.controller";
|
|
||||||
private AliasModel mAliasModel;
|
|
||||||
private JTable mAliasTable;
|
|
||||||
private TableFilterHeader mTableFilterHeader;
|
|
||||||
private AliasEditor mAliasEditor;
|
|
||||||
private MultipleAliasEditor mMultipleAliasEditor;
|
|
||||||
private JideSplitPane mSplitPane;
|
|
||||||
private UserPreferences mUserPreferences;
|
|
||||||
|
|
||||||
private static final String NEW_ALIAS = "New";
|
|
||||||
private static final String COPY_ALIAS = "Copy";
|
|
||||||
private static final String DELETE_ALIAS = "Delete";
|
|
||||||
|
|
||||||
private JButton mNewButton = new JButton(NEW_ALIAS);
|
|
||||||
private JButton mCopyButton = new JButton(COPY_ALIAS);
|
|
||||||
private JButton mDeleteButton = new JButton(DELETE_ALIAS);
|
|
||||||
|
|
||||||
private IconCellRenderer mIconCellRenderer;
|
|
||||||
private JTableColumnWidthMonitor mColumnWidthMonitor;
|
|
||||||
|
|
||||||
public AliasController(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager,
|
|
||||||
UserPreferences userPreferences)
|
|
||||||
{
|
|
||||||
mAliasModel = aliasModel;
|
|
||||||
mAliasEditor = new AliasEditor(mAliasModel, broadcastModel, iconManager);
|
|
||||||
mMultipleAliasEditor = new MultipleAliasEditor(mAliasModel, broadcastModel, iconManager);
|
|
||||||
mIconCellRenderer = new IconCellRenderer(iconManager);
|
|
||||||
mUserPreferences = userPreferences;
|
|
||||||
|
|
||||||
init();
|
|
||||||
|
|
||||||
mAliasModel.addListener(mAliasEditor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill]"));
|
|
||||||
|
|
||||||
//System Configuration View and Editor
|
|
||||||
mAliasTable = new JTable(mAliasModel);
|
|
||||||
mAliasTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
|
||||||
mAliasTable.getSelectionModel().addListSelectionListener(this);
|
|
||||||
mAliasTable.setAutoCreateRowSorter(true);
|
|
||||||
|
|
||||||
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_COLOR).setCellRenderer(new ColorCellRenderer());
|
|
||||||
|
|
||||||
mAliasTable.getColumnModel().getColumn(AliasModel.COLUMN_ICON).setCellRenderer(mIconCellRenderer);
|
|
||||||
|
|
||||||
mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mAliasTable, TABLE_PREFERENCE_KEY);
|
|
||||||
|
|
||||||
mTableFilterHeader = new TableFilterHeader(mAliasTable, AutoChoices.ENABLED);
|
|
||||||
mTableFilterHeader.setFilterOnUpdates(true);
|
|
||||||
|
|
||||||
JScrollPane tableScroller = new JScrollPane(mAliasTable);
|
|
||||||
|
|
||||||
JPanel buttonsPanel = new JPanel();
|
|
||||||
|
|
||||||
buttonsPanel.setLayout(new MigLayout("insets 0 0 0 0",
|
|
||||||
"[grow,fill][grow,fill][grow,fill]", "[]"));
|
|
||||||
|
|
||||||
mNewButton.addActionListener(this);
|
|
||||||
mNewButton.setToolTipText("Adds a new alias");
|
|
||||||
buttonsPanel.add(mNewButton);
|
|
||||||
|
|
||||||
mCopyButton.addActionListener(this);
|
|
||||||
mCopyButton.setEnabled(false);
|
|
||||||
mCopyButton.setToolTipText("Creates a copy of the currently selected alias and adds it");
|
|
||||||
buttonsPanel.add(mCopyButton);
|
|
||||||
|
|
||||||
mDeleteButton.addActionListener(this);
|
|
||||||
mDeleteButton.setEnabled(false);
|
|
||||||
mDeleteButton.setToolTipText("Deletes the currently selected alias");
|
|
||||||
buttonsPanel.add(mDeleteButton);
|
|
||||||
|
|
||||||
JPanel listAndButtonsPanel = new JPanel();
|
|
||||||
|
|
||||||
listAndButtonsPanel.setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]",
|
|
||||||
"[grow,fill][]"));
|
|
||||||
|
|
||||||
listAndButtonsPanel.add(tableScroller, "wrap");
|
|
||||||
listAndButtonsPanel.add(buttonsPanel);
|
|
||||||
|
|
||||||
mSplitPane = new JideSplitPane(JideSplitPane.HORIZONTAL_SPLIT);
|
|
||||||
mSplitPane.setDividerSize(5);
|
|
||||||
mSplitPane.setShowGripper(true);
|
|
||||||
mSplitPane.add(listAndButtonsPanel);
|
|
||||||
mSplitPane.add(mAliasEditor);
|
|
||||||
|
|
||||||
add(mSplitPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the editor argument as the currently visible alias editor
|
|
||||||
*/
|
|
||||||
private void setEditor(Editor<?> editor)
|
|
||||||
{
|
|
||||||
if(mSplitPane.getComponentCount() == 3)
|
|
||||||
{
|
|
||||||
Component component = mSplitPane.getComponent(2);
|
|
||||||
|
|
||||||
if(component instanceof Editor<?> && component != editor)
|
|
||||||
{
|
|
||||||
//Get current divider location so that we can reapply it after
|
|
||||||
//changing out the editors, so that the interface doesn't move
|
|
||||||
int location = mSplitPane.getDividerLocation(0);
|
|
||||||
|
|
||||||
((Editor<?>) component).setItem(null);
|
|
||||||
|
|
||||||
mSplitPane.remove(component);
|
|
||||||
editor.setPreferredSize(new Dimension(100, 100));
|
|
||||||
mSplitPane.add(editor);
|
|
||||||
|
|
||||||
mSplitPane.validate();
|
|
||||||
mSplitPane.setDividerLocation(0, location);
|
|
||||||
mSplitPane.repaint();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Alias getAlias(int selectedRow)
|
|
||||||
{
|
|
||||||
if(selectedRow >= 0)
|
|
||||||
{
|
|
||||||
int index = mAliasTable.convertRowIndexToModel(selectedRow);
|
|
||||||
|
|
||||||
return mAliasModel.getAliasAtIndex(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void valueChanged(ListSelectionEvent event)
|
|
||||||
{
|
|
||||||
//Limits event firing to only when selection is complete
|
|
||||||
if(!event.getValueIsAdjusting())
|
|
||||||
{
|
|
||||||
int[] selectedRows = mAliasTable.getSelectedRows();
|
|
||||||
|
|
||||||
if(selectedRows.length == 0)
|
|
||||||
{
|
|
||||||
mAliasEditor.setItem(null);
|
|
||||||
mCopyButton.setEnabled(false);
|
|
||||||
mDeleteButton.setEnabled(false);
|
|
||||||
}
|
|
||||||
else if(selectedRows.length == 1)
|
|
||||||
{
|
|
||||||
setEditor(mAliasEditor);
|
|
||||||
|
|
||||||
Alias selectedAlias = getAlias(selectedRows[0]);
|
|
||||||
|
|
||||||
mAliasEditor.setItem(selectedAlias);
|
|
||||||
|
|
||||||
if(selectedAlias != null)
|
|
||||||
{
|
|
||||||
mCopyButton.setEnabled(true);
|
|
||||||
mDeleteButton.setEnabled(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mCopyButton.setEnabled(false);
|
|
||||||
mDeleteButton.setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setEditor(mMultipleAliasEditor);
|
|
||||||
|
|
||||||
mCopyButton.setEnabled(true);
|
|
||||||
mDeleteButton.setEnabled(true);
|
|
||||||
|
|
||||||
List<Alias> selectedAliases = new ArrayList<Alias>();
|
|
||||||
|
|
||||||
for(int selectedRow : selectedRows)
|
|
||||||
{
|
|
||||||
Alias alias = getAlias(selectedRow);
|
|
||||||
|
|
||||||
selectedAliases.add(alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
mMultipleAliasEditor.setItem(selectedAliases);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the alias to the alias table/model and scrolls the view it
|
|
||||||
*/
|
|
||||||
private void addAlias(Alias alias)
|
|
||||||
{
|
|
||||||
//Remove any column headers so that the newly added alias shows correctly.
|
|
||||||
mTableFilterHeader.resetFilter();
|
|
||||||
|
|
||||||
int index = mAliasModel.addAlias(alias);
|
|
||||||
|
|
||||||
if(index >= 0)
|
|
||||||
{
|
|
||||||
int translatedIndex = mAliasTable.convertRowIndexToView(index);
|
|
||||||
mAliasTable.setRowSelectionInterval(translatedIndex, translatedIndex);
|
|
||||||
mAliasTable.scrollRectToVisible(
|
|
||||||
new Rectangle(mAliasTable.getCellRect(translatedIndex, 0, true)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Alias> getSelectedAliases()
|
|
||||||
{
|
|
||||||
List<Alias> selected = new ArrayList<>();
|
|
||||||
|
|
||||||
int[] rows = mAliasTable.getSelectedRows();
|
|
||||||
|
|
||||||
for(int row : rows)
|
|
||||||
{
|
|
||||||
if(row >= 0)
|
|
||||||
{
|
|
||||||
Alias alias = mAliasModel.getAliasAtIndex(mAliasTable.convertRowIndexToModel(row));
|
|
||||||
|
|
||||||
if(alias != null)
|
|
||||||
{
|
|
||||||
selected.add(alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return selected;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responds to New, Copy and Delete Channel button invocations
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent event)
|
|
||||||
{
|
|
||||||
switch(event.getActionCommand())
|
|
||||||
{
|
|
||||||
case NEW_ALIAS:
|
|
||||||
addAlias(new Alias("New Alias"));
|
|
||||||
break;
|
|
||||||
case COPY_ALIAS:
|
|
||||||
for(Alias alias : getSelectedAliases())
|
|
||||||
{
|
|
||||||
addAlias(AliasFactory.copyOf(alias));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DELETE_ALIAS:
|
|
||||||
List<Alias> toDelete = getSelectedAliases();
|
|
||||||
|
|
||||||
if(toDelete != null && !toDelete.isEmpty())
|
|
||||||
{
|
|
||||||
String title = toDelete.size() == 1 ? "Delete Alias?" : "Delete Aliases?";
|
|
||||||
String prompt = toDelete.size() == 1 ? "Do you want to delete this alias?" :
|
|
||||||
"Do you want to delete these " + toDelete.size() + " aliases?";
|
|
||||||
|
|
||||||
int choice = JOptionPane.showConfirmDialog(AliasController.this,
|
|
||||||
prompt, title, JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
|
|
||||||
|
|
||||||
if(choice == JOptionPane.YES_OPTION)
|
|
||||||
{
|
|
||||||
for(Alias alias : toDelete)
|
|
||||||
{
|
|
||||||
mAliasModel.removeAlias(alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Colorizes the cell based on the cell's integer value
|
|
||||||
*/
|
|
||||||
public class ColorCellRenderer extends DefaultTableCellRenderer
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getTableCellRendererComponent(JTable table,
|
|
||||||
Object value, boolean isSelected, boolean hasFocus, int row,
|
|
||||||
int column)
|
|
||||||
{
|
|
||||||
JLabel label = (JLabel) super.getTableCellRendererComponent(table,
|
|
||||||
value, isSelected, hasFocus, row, column);
|
|
||||||
|
|
||||||
label.setBackground(new Color((int) value));
|
|
||||||
|
|
||||||
label.setText("");
|
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays cell's icon and name
|
|
||||||
*/
|
|
||||||
public class IconCellRenderer extends DefaultTableCellRenderer
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private IconManager mIconManager;
|
|
||||||
|
|
||||||
public IconCellRenderer(IconManager iconManager)
|
|
||||||
{
|
|
||||||
mIconManager = iconManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getTableCellRendererComponent(JTable table,
|
|
||||||
Object value, boolean isSelected, boolean hasFocus, int row,
|
|
||||||
int column)
|
|
||||||
{
|
|
||||||
JLabel label = (JLabel) super.getTableCellRendererComponent(table,
|
|
||||||
value, isSelected, hasFocus, row, column);
|
|
||||||
|
|
||||||
ImageIcon icon = mIconManager.getIcon(label.getText(), 12);
|
|
||||||
|
|
||||||
if(icon != null)
|
|
||||||
{
|
|
||||||
label.setIcon(icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
return label;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,157 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias;
|
|
||||||
|
|
||||||
import com.jidesoft.swing.JideTabbedPane;
|
|
||||||
import io.github.dsheirer.alias.action.AliasActionEditor;
|
|
||||||
import io.github.dsheirer.alias.id.AliasIdentifierEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class AliasEditor extends Editor<Alias> implements ActionListener, Listener<AliasEvent>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String DEFAULT_NAME = "select an alias";
|
|
||||||
|
|
||||||
private AliasModel mAliasModel;
|
|
||||||
|
|
||||||
private JLabel mAliasLabel;
|
|
||||||
private AliasNameEditor mAliasNameEditor;
|
|
||||||
private AliasIdentifierEditor mAliasIdentifierEditor;
|
|
||||||
private AliasActionEditor mAliasActionEditor;
|
|
||||||
|
|
||||||
public AliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager )
|
|
||||||
{
|
|
||||||
mAliasModel = aliasModel;
|
|
||||||
mAliasNameEditor = new AliasNameEditor( mAliasModel, iconManager );
|
|
||||||
mAliasIdentifierEditor = new AliasIdentifierEditor( aliasModel, broadcastModel );
|
|
||||||
mAliasActionEditor = new AliasActionEditor( aliasModel );
|
|
||||||
|
|
||||||
mAliasModel.addListener( this );
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( Alias alias )
|
|
||||||
{
|
|
||||||
super.setItem( alias );
|
|
||||||
|
|
||||||
if( hasItem() )
|
|
||||||
{
|
|
||||||
mAliasLabel.setText( getItem().getName() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mAliasLabel.setText( DEFAULT_NAME );
|
|
||||||
}
|
|
||||||
|
|
||||||
mAliasNameEditor.setItem( alias );
|
|
||||||
mAliasIdentifierEditor.setItem( alias );
|
|
||||||
mAliasActionEditor.setItem( alias );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[grow,fill][grow,fill]",
|
|
||||||
"[][][][][][grow,fill]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Alias:" ), "align right" );
|
|
||||||
mAliasLabel = new JLabel( DEFAULT_NAME );
|
|
||||||
add( mAliasLabel, "align left" );
|
|
||||||
|
|
||||||
add( new JSeparator( JSeparator.HORIZONTAL ), "span,growx,push" );
|
|
||||||
|
|
||||||
JideTabbedPane tabs = new JideTabbedPane();
|
|
||||||
tabs.setFont( this.getFont() );
|
|
||||||
tabs.setForeground( Color.BLACK );
|
|
||||||
|
|
||||||
tabs.addTab( "Alias", mAliasNameEditor );
|
|
||||||
tabs.addTab( "Audio / Identifier", mAliasIdentifierEditor );
|
|
||||||
tabs.addTab( "Action", mAliasActionEditor );
|
|
||||||
add( tabs, "span,grow" );
|
|
||||||
|
|
||||||
//Playlist management buttons
|
|
||||||
JButton btnSave = new JButton( "Save" );
|
|
||||||
btnSave.setToolTipText( "Save alias changes to the playlist" );
|
|
||||||
btnSave.addActionListener( AliasEditor.this );
|
|
||||||
add( btnSave );
|
|
||||||
|
|
||||||
JButton btnReset = new JButton( "Reset" );
|
|
||||||
btnReset.setToolTipText( "Reset alias changes since last save" );
|
|
||||||
btnReset.addActionListener( AliasEditor.this );
|
|
||||||
add( btnReset, "wrap" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive( AliasEvent event )
|
|
||||||
{
|
|
||||||
//If this is the currently displayed alias, reload it
|
|
||||||
if( hasItem() && getItem() == event.getAlias() )
|
|
||||||
{
|
|
||||||
switch( event.getEvent() )
|
|
||||||
{
|
|
||||||
case CHANGE:
|
|
||||||
//Alias changed - reset the editor with changed alias
|
|
||||||
setItem( event.getAlias() );
|
|
||||||
break;
|
|
||||||
case DELETE:
|
|
||||||
setItem( null );
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
if( hasItem() )
|
|
||||||
{
|
|
||||||
String command = e.getActionCommand();
|
|
||||||
|
|
||||||
if( command.contentEquals( "Save" ) )
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
else if( command.contentEquals( "Reset" ) )
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
mAliasNameEditor.save();
|
|
||||||
mAliasIdentifierEditor.save();
|
|
||||||
mAliasActionEditor.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* * ******************************************************************************
|
* * ******************************************************************************
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* *
|
* *
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
* * 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
|
* * it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,55 +24,37 @@ package io.github.dsheirer.alias;
|
|||||||
import io.github.dsheirer.alias.action.AliasAction;
|
import io.github.dsheirer.alias.action.AliasAction;
|
||||||
import io.github.dsheirer.alias.action.AliasActionType;
|
import io.github.dsheirer.alias.action.AliasActionType;
|
||||||
import io.github.dsheirer.alias.action.beep.BeepAction;
|
import io.github.dsheirer.alias.action.beep.BeepAction;
|
||||||
import io.github.dsheirer.alias.action.beep.BeepActionEditor;
|
|
||||||
import io.github.dsheirer.alias.action.clip.ClipAction;
|
import io.github.dsheirer.alias.action.clip.ClipAction;
|
||||||
import io.github.dsheirer.alias.action.clip.ClipActionEditor;
|
|
||||||
import io.github.dsheirer.alias.action.script.ScriptAction;
|
import io.github.dsheirer.alias.action.script.ScriptAction;
|
||||||
import io.github.dsheirer.alias.action.script.ScriptActionEditor;
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
import io.github.dsheirer.alias.id.AliasID;
|
||||||
import io.github.dsheirer.alias.id.AliasIDType;
|
import io.github.dsheirer.alias.id.AliasIDType;
|
||||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
||||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannelEditor;
|
|
||||||
import io.github.dsheirer.alias.id.esn.ESNEditor;
|
|
||||||
import io.github.dsheirer.alias.id.esn.Esn;
|
import io.github.dsheirer.alias.id.esn.Esn;
|
||||||
import io.github.dsheirer.alias.id.legacy.fleetsync.FleetsyncID;
|
import io.github.dsheirer.alias.id.legacy.fleetsync.FleetsyncID;
|
||||||
import io.github.dsheirer.alias.id.legacy.fleetsync.FleetsyncIDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.legacy.mdc.MDC1200ID;
|
import io.github.dsheirer.alias.id.legacy.mdc.MDC1200ID;
|
||||||
import io.github.dsheirer.alias.id.legacy.mdc.MDC1200IDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.legacy.mobileID.MINEditor;
|
|
||||||
import io.github.dsheirer.alias.id.legacy.mobileID.Min;
|
import io.github.dsheirer.alias.id.legacy.mobileID.Min;
|
||||||
import io.github.dsheirer.alias.id.legacy.mpt1327.MPT1327ID;
|
import io.github.dsheirer.alias.id.legacy.mpt1327.MPT1327ID;
|
||||||
import io.github.dsheirer.alias.id.legacy.mpt1327.MPT1327IDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.legacy.nonrecordable.NonRecordable;
|
import io.github.dsheirer.alias.id.legacy.nonrecordable.NonRecordable;
|
||||||
import io.github.dsheirer.alias.id.legacy.nonrecordable.NonRecordableEditor;
|
|
||||||
import io.github.dsheirer.alias.id.legacy.siteID.SiteID;
|
import io.github.dsheirer.alias.id.legacy.siteID.SiteID;
|
||||||
import io.github.dsheirer.alias.id.legacy.siteID.SiteIDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.legacy.talkgroup.LegacyTalkgroupID;
|
import io.github.dsheirer.alias.id.legacy.talkgroup.LegacyTalkgroupID;
|
||||||
import io.github.dsheirer.alias.id.legacy.talkgroup.LegacyTalkgroupIDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.legacy.uniqueID.UniqueID;
|
import io.github.dsheirer.alias.id.legacy.uniqueID.UniqueID;
|
||||||
import io.github.dsheirer.alias.id.legacy.uniqueID.UniqueIDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.lojack.LoJackFunctionAndID;
|
import io.github.dsheirer.alias.id.lojack.LoJackFunctionAndID;
|
||||||
import io.github.dsheirer.alias.id.lojack.LoJackIDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.priority.Priority;
|
import io.github.dsheirer.alias.id.priority.Priority;
|
||||||
import io.github.dsheirer.alias.id.priority.PriorityEditor;
|
|
||||||
import io.github.dsheirer.alias.id.radio.Radio;
|
import io.github.dsheirer.alias.id.radio.Radio;
|
||||||
import io.github.dsheirer.alias.id.radio.RadioEditor;
|
|
||||||
import io.github.dsheirer.alias.id.radio.RadioRange;
|
import io.github.dsheirer.alias.id.radio.RadioRange;
|
||||||
import io.github.dsheirer.alias.id.radio.RadioRangeEditor;
|
|
||||||
import io.github.dsheirer.alias.id.record.Record;
|
import io.github.dsheirer.alias.id.record.Record;
|
||||||
import io.github.dsheirer.alias.id.record.RecordEditor;
|
import io.github.dsheirer.alias.id.status.UnitStatusID;
|
||||||
import io.github.dsheirer.alias.id.status.StatusID;
|
import io.github.dsheirer.alias.id.status.UserStatusID;
|
||||||
import io.github.dsheirer.alias.id.status.StatusIDEditor;
|
|
||||||
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
|
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
|
||||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupEditor;
|
|
||||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
|
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
|
||||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRangeEditor;
|
import io.github.dsheirer.alias.id.tone.TonesID;
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
import org.slf4j.Logger;
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
import org.slf4j.LoggerFactory;
|
||||||
import io.github.dsheirer.gui.editor.EmptyEditor;
|
|
||||||
|
|
||||||
public class AliasFactory
|
public class AliasFactory
|
||||||
{
|
{
|
||||||
|
private static final Logger mLog = LoggerFactory.getLogger(AliasFactory.class);
|
||||||
|
|
||||||
public static AliasID copyOf(AliasID id)
|
public static AliasID copyOf(AliasID id)
|
||||||
{
|
{
|
||||||
switch(id.getType())
|
switch(id.getType())
|
||||||
@@ -87,11 +69,6 @@ public class AliasFactory
|
|||||||
Esn copyESN = new Esn();
|
Esn copyESN = new Esn();
|
||||||
copyESN.setEsn(originalESN.getEsn());
|
copyESN.setEsn(originalESN.getEsn());
|
||||||
return copyESN;
|
return copyESN;
|
||||||
case LTR_NET_UID:
|
|
||||||
UniqueID originalUniqueID = (UniqueID)id;
|
|
||||||
UniqueID copyUniqueID = new UniqueID();
|
|
||||||
copyUniqueID.setUid(originalUniqueID.getUid());
|
|
||||||
return copyUniqueID;
|
|
||||||
case LOJACK:
|
case LOJACK:
|
||||||
LoJackFunctionAndID originalLoJackFunctionAndID = (LoJackFunctionAndID)id;
|
LoJackFunctionAndID originalLoJackFunctionAndID = (LoJackFunctionAndID)id;
|
||||||
LoJackFunctionAndID copyLoJackFunctionAndID = new LoJackFunctionAndID();
|
LoJackFunctionAndID copyLoJackFunctionAndID = new LoJackFunctionAndID();
|
||||||
@@ -111,11 +88,13 @@ public class AliasFactory
|
|||||||
case RADIO_ID:
|
case RADIO_ID:
|
||||||
Radio originalRadio = (Radio)id;
|
Radio originalRadio = (Radio)id;
|
||||||
Radio copyRadio = new Radio(originalRadio.getProtocol(), originalRadio.getValue());
|
Radio copyRadio = new Radio(originalRadio.getProtocol(), originalRadio.getValue());
|
||||||
|
copyRadio.setOverlap(originalRadio.overlapProperty().get());
|
||||||
return copyRadio;
|
return copyRadio;
|
||||||
case RADIO_ID_RANGE:
|
case RADIO_ID_RANGE:
|
||||||
RadioRange originalRadioRange = (RadioRange)id;
|
RadioRange originalRadioRange = (RadioRange)id;
|
||||||
RadioRange copyRadioRange = new RadioRange(originalRadioRange.getProtocol(), originalRadioRange.getMinRadio(),
|
RadioRange copyRadioRange = new RadioRange(originalRadioRange.getProtocol(), originalRadioRange.getMinRadio(),
|
||||||
originalRadioRange.getMaxRadio());
|
originalRadioRange.getMaxRadio());
|
||||||
|
copyRadioRange.setOverlap(originalRadioRange.overlapProperty().get());
|
||||||
return copyRadioRange;
|
return copyRadioRange;
|
||||||
case RECORD:
|
case RECORD:
|
||||||
return new Record();
|
return new Record();
|
||||||
@@ -125,27 +104,45 @@ public class AliasFactory
|
|||||||
copySiteID.setSite(originalSiteID.getSite());
|
copySiteID.setSite(originalSiteID.getSite());
|
||||||
return copySiteID;
|
return copySiteID;
|
||||||
case STATUS:
|
case STATUS:
|
||||||
StatusID originalStatusID = (StatusID)id;
|
UserStatusID originalUserStatusID = (UserStatusID)id;
|
||||||
StatusID copyStatusID = new StatusID();
|
UserStatusID copyUserStatusID = new UserStatusID();
|
||||||
copyStatusID.setStatus(originalStatusID.getStatus());
|
copyUserStatusID.setStatus(originalUserStatusID.getStatus());
|
||||||
return copyStatusID;
|
copyUserStatusID.setOverlap(originalUserStatusID.overlapProperty().get());
|
||||||
|
return copyUserStatusID;
|
||||||
case TALKGROUP:
|
case TALKGROUP:
|
||||||
Talkgroup originalTalkgroup = (Talkgroup)id;
|
Talkgroup originalTalkgroup = (Talkgroup)id;
|
||||||
Talkgroup copyTalkgroup = new Talkgroup(originalTalkgroup.getProtocol(), originalTalkgroup.getValue());
|
Talkgroup copyTalkgroup = new Talkgroup(originalTalkgroup.getProtocol(), originalTalkgroup.getValue());
|
||||||
|
copyTalkgroup.setOverlap(originalTalkgroup.overlapProperty().get());
|
||||||
return copyTalkgroup;
|
return copyTalkgroup;
|
||||||
case TALKGROUP_RANGE:
|
case TALKGROUP_RANGE:
|
||||||
TalkgroupRange originalRange = (TalkgroupRange)id;
|
TalkgroupRange originalRange = (TalkgroupRange)id;
|
||||||
TalkgroupRange copyRange = new TalkgroupRange(originalRange.getProtocol(), originalRange.getMinTalkgroup(),
|
TalkgroupRange copyRange = new TalkgroupRange(originalRange.getProtocol(), originalRange.getMinTalkgroup(),
|
||||||
originalRange.getMaxTalkgroup());
|
originalRange.getMaxTalkgroup());
|
||||||
|
copyRange.setOverlap(originalRange.overlapProperty().get());
|
||||||
return copyRange;
|
return copyRange;
|
||||||
|
case TONES:
|
||||||
|
TonesID originalTones = (TonesID)id;
|
||||||
|
TonesID copyTones = new TonesID();
|
||||||
|
copyTones.setToneSequence(originalTones.getToneSequence().copyOf());
|
||||||
|
return copyTones;
|
||||||
|
case UNIT_STATUS:
|
||||||
|
UnitStatusID originalUnitStatus = (UnitStatusID)id;
|
||||||
|
UnitStatusID copyUnitStatusID = new UnitStatusID();
|
||||||
|
copyUnitStatusID.setStatus(originalUnitStatus.getStatus());
|
||||||
|
copyUnitStatusID.setOverlap(originalUnitStatus.overlapProperty().get());
|
||||||
|
return copyUnitStatusID;
|
||||||
|
|
||||||
//Legacy identifiers ... not supported
|
//Legacy identifiers ... not supported
|
||||||
case FLEETSYNC:
|
case FLEETSYNC:
|
||||||
case LEGACY_TALKGROUP:
|
case LEGACY_TALKGROUP:
|
||||||
|
case LTR_NET_UID:
|
||||||
case MDC1200:
|
case MDC1200:
|
||||||
case MPT1327:
|
case MPT1327:
|
||||||
case NON_RECORDABLE:
|
case NON_RECORDABLE:
|
||||||
|
return null;
|
||||||
default:
|
default:
|
||||||
|
mLog.warn("Unrecognized Alias ID Type [" + id.getType() + "] cannot make copy of instance");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@@ -155,7 +152,11 @@ public class AliasFactory
|
|||||||
{
|
{
|
||||||
if(action instanceof BeepAction)
|
if(action instanceof BeepAction)
|
||||||
{
|
{
|
||||||
return new BeepAction();
|
BeepAction original = (BeepAction)action;
|
||||||
|
BeepAction copyBeep = new BeepAction();
|
||||||
|
copyBeep.setInterval(original.getInterval());
|
||||||
|
copyBeep.setPeriod(original.getPeriod());
|
||||||
|
return copyBeep;
|
||||||
}
|
}
|
||||||
else if(action instanceof ClipAction)
|
else if(action instanceof ClipAction)
|
||||||
{
|
{
|
||||||
@@ -182,12 +183,12 @@ public class AliasFactory
|
|||||||
public static Alias copyOf(Alias original)
|
public static Alias copyOf(Alias original)
|
||||||
{
|
{
|
||||||
Alias copy = new Alias(original.getName());
|
Alias copy = new Alias(original.getName());
|
||||||
copy.setList(original.getList());
|
copy.setAliasListName(original.getAliasListName());
|
||||||
copy.setGroup(original.getGroup());
|
copy.setGroup(original.getGroup());
|
||||||
copy.setColor(original.getColor());
|
copy.setColor(original.getColor());
|
||||||
copy.setIconName(original.getIconName());
|
copy.setIconName(original.getIconName());
|
||||||
|
|
||||||
for(AliasID id : original.getId())
|
for(AliasID id : original.getAliasIdentifiers())
|
||||||
{
|
{
|
||||||
AliasID copyID = copyOf(id);
|
AliasID copyID = copyOf(id);
|
||||||
|
|
||||||
@@ -197,7 +198,7 @@ public class AliasFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(AliasAction action : original.getAction())
|
for(AliasAction action : original.getAliasActions())
|
||||||
{
|
{
|
||||||
AliasAction copyAction = copyOf(action);
|
AliasAction copyAction = copyOf(action);
|
||||||
|
|
||||||
@@ -210,77 +211,6 @@ public class AliasFactory
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Editor<AliasID> getEditor(AliasID aliasID, BroadcastModel broadcastModel)
|
|
||||||
{
|
|
||||||
if(aliasID != null)
|
|
||||||
{
|
|
||||||
switch(aliasID.getType())
|
|
||||||
{
|
|
||||||
case BROADCAST_CHANNEL:
|
|
||||||
return new BroadcastChannelEditor(aliasID, broadcastModel);
|
|
||||||
case ESN:
|
|
||||||
return new ESNEditor(aliasID);
|
|
||||||
case LTR_NET_UID:
|
|
||||||
return new UniqueIDEditor(aliasID);
|
|
||||||
case LOJACK:
|
|
||||||
return new LoJackIDEditor(aliasID);
|
|
||||||
case MIN:
|
|
||||||
return new MINEditor(aliasID);
|
|
||||||
case PRIORITY:
|
|
||||||
return new PriorityEditor(aliasID);
|
|
||||||
case RADIO_ID:
|
|
||||||
return new RadioEditor(aliasID);
|
|
||||||
case RADIO_ID_RANGE:
|
|
||||||
return new RadioRangeEditor(aliasID);
|
|
||||||
case RECORD:
|
|
||||||
return new RecordEditor(aliasID);
|
|
||||||
case SITE:
|
|
||||||
return new SiteIDEditor(aliasID);
|
|
||||||
case STATUS:
|
|
||||||
return new StatusIDEditor(aliasID);
|
|
||||||
case TALKGROUP:
|
|
||||||
return new TalkgroupEditor(aliasID);
|
|
||||||
case TALKGROUP_RANGE:
|
|
||||||
return new TalkgroupRangeEditor(aliasID);
|
|
||||||
|
|
||||||
case FLEETSYNC:
|
|
||||||
return new FleetsyncIDEditor(aliasID);
|
|
||||||
case LEGACY_TALKGROUP:
|
|
||||||
return new LegacyTalkgroupIDEditor(aliasID);
|
|
||||||
case MDC1200:
|
|
||||||
return new MDC1200IDEditor(aliasID);
|
|
||||||
case MPT1327:
|
|
||||||
return new MPT1327IDEditor(aliasID);
|
|
||||||
case NON_RECORDABLE:
|
|
||||||
return new NonRecordableEditor(aliasID);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new EmptyEditor<AliasID>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Editor<AliasAction> getEditor(AliasAction aliasAction)
|
|
||||||
{
|
|
||||||
if(aliasAction != null)
|
|
||||||
{
|
|
||||||
switch(aliasAction.getType())
|
|
||||||
{
|
|
||||||
case BEEP:
|
|
||||||
return new BeepActionEditor(aliasAction);
|
|
||||||
case CLIP:
|
|
||||||
return new ClipActionEditor(aliasAction);
|
|
||||||
case SCRIPT:
|
|
||||||
return new ScriptActionEditor(aliasAction);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new EmptyEditor<AliasAction>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AliasID getAliasID(AliasIDType type)
|
public static AliasID getAliasID(AliasIDType type)
|
||||||
{
|
{
|
||||||
switch(type)
|
switch(type)
|
||||||
@@ -318,7 +248,7 @@ public class AliasFactory
|
|||||||
case SITE:
|
case SITE:
|
||||||
return new SiteID();
|
return new SiteID();
|
||||||
case STATUS:
|
case STATUS:
|
||||||
return new StatusID();
|
return new UserStatusID();
|
||||||
case LEGACY_TALKGROUP:
|
case LEGACY_TALKGROUP:
|
||||||
return new LegacyTalkgroupID();
|
return new LegacyTalkgroupID();
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* * ******************************************************************************
|
* * ******************************************************************************
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* *
|
* *
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
* * 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
|
* * it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,9 +28,11 @@ import io.github.dsheirer.alias.id.esn.Esn;
|
|||||||
import io.github.dsheirer.alias.id.priority.Priority;
|
import io.github.dsheirer.alias.id.priority.Priority;
|
||||||
import io.github.dsheirer.alias.id.radio.Radio;
|
import io.github.dsheirer.alias.id.radio.Radio;
|
||||||
import io.github.dsheirer.alias.id.radio.RadioRange;
|
import io.github.dsheirer.alias.id.radio.RadioRange;
|
||||||
import io.github.dsheirer.alias.id.status.StatusID;
|
import io.github.dsheirer.alias.id.status.UnitStatusID;
|
||||||
|
import io.github.dsheirer.alias.id.status.UserStatusID;
|
||||||
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
|
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
|
||||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
|
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
|
||||||
|
import io.github.dsheirer.alias.id.tone.TonesID;
|
||||||
import io.github.dsheirer.identifier.Identifier;
|
import io.github.dsheirer.identifier.Identifier;
|
||||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||||
import io.github.dsheirer.identifier.esn.ESNIdentifier;
|
import io.github.dsheirer.identifier.esn.ESNIdentifier;
|
||||||
@@ -40,8 +42,12 @@ import io.github.dsheirer.identifier.radio.RadioIdentifier;
|
|||||||
import io.github.dsheirer.identifier.status.UnitStatusIdentifier;
|
import io.github.dsheirer.identifier.status.UnitStatusIdentifier;
|
||||||
import io.github.dsheirer.identifier.status.UserStatusIdentifier;
|
import io.github.dsheirer.identifier.status.UserStatusIdentifier;
|
||||||
import io.github.dsheirer.identifier.talkgroup.TalkgroupIdentifier;
|
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.protocol.Protocol;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -57,9 +63,12 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
private Map<Protocol,TalkgroupAliasList> mTalkgroupProtocolMap = new EnumMap<>(Protocol.class);
|
private Map<Protocol,TalkgroupAliasList> mTalkgroupProtocolMap = new EnumMap<>(Protocol.class);
|
||||||
private Map<Protocol,RadioAliasList> mRadioProtocolMap = new EnumMap<>(Protocol.class);
|
private Map<Protocol,RadioAliasList> mRadioProtocolMap = new EnumMap<>(Protocol.class);
|
||||||
private Map<String,Alias> mESNMap = new HashMap<>();
|
private Map<String,Alias> mESNMap = new HashMap<>();
|
||||||
private Map<Integer,Alias> mStatusMap = new HashMap<>();
|
private Map<Integer,Alias> mUnitStatusMap = new HashMap<>();
|
||||||
|
private Map<Integer,Alias> mUserStatusMap = new HashMap<>();
|
||||||
|
private Map<ToneSequence,Alias> mToneSequenceMap = new HashMap<>();
|
||||||
private boolean mHasAliasActions = false;
|
private boolean mHasAliasActions = false;
|
||||||
private String mName;
|
private String mName;
|
||||||
|
private ObservableList<Alias> mAliases = FXCollections.observableArrayList(Alias.extractor());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of aliases where all aliases share the same list name. Contains
|
* List of aliases where all aliases share the same list name. Contains
|
||||||
@@ -72,6 +81,14 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
mName = name;
|
mName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable list of aliases contained in this alias list
|
||||||
|
*/
|
||||||
|
public ObservableList<Alias> aliases()
|
||||||
|
{
|
||||||
|
return mAliases;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the alias to this list
|
* Adds the alias to this list
|
||||||
*/
|
*/
|
||||||
@@ -79,7 +96,7 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
{
|
{
|
||||||
if(alias != null)
|
if(alias != null)
|
||||||
{
|
{
|
||||||
for(AliasID aliasID : alias.getId())
|
for(AliasID aliasID : alias.getAliasIdentifiers())
|
||||||
{
|
{
|
||||||
addAliasID(aliasID, alias);
|
addAliasID(aliasID, alias);
|
||||||
}
|
}
|
||||||
@@ -89,6 +106,8 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
{
|
{
|
||||||
mHasAliasActions = true;
|
mHasAliasActions = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mAliases.add(alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -163,7 +182,67 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STATUS:
|
case STATUS:
|
||||||
mStatusMap.put(((StatusID) id).getStatus(), alias);
|
int userStatus = ((UserStatusID)id).getStatus();
|
||||||
|
|
||||||
|
if(mUserStatusMap.containsKey(userStatus))
|
||||||
|
{
|
||||||
|
id.setOverlap(true);
|
||||||
|
|
||||||
|
Alias existing = mUserStatusMap.get(userStatus);
|
||||||
|
|
||||||
|
for(AliasID aliasID: existing.getAliasIdentifiers())
|
||||||
|
{
|
||||||
|
if(aliasID instanceof UserStatusID && ((UserStatusID)aliasID).getStatus() == userStatus)
|
||||||
|
{
|
||||||
|
aliasID.setOverlap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mUserStatusMap.put(userStatus, alias);
|
||||||
|
break;
|
||||||
|
case UNIT_STATUS:
|
||||||
|
int unitStatus = ((UnitStatusID)id).getStatus();
|
||||||
|
|
||||||
|
if(mUnitStatusMap.containsKey(unitStatus))
|
||||||
|
{
|
||||||
|
id.setOverlap(true);
|
||||||
|
|
||||||
|
Alias existing = mUnitStatusMap.get(unitStatus);
|
||||||
|
|
||||||
|
for(AliasID aliasID: existing.getAliasIdentifiers())
|
||||||
|
{
|
||||||
|
if(aliasID instanceof UnitStatusID && ((UnitStatusID)aliasID).getStatus() == unitStatus)
|
||||||
|
{
|
||||||
|
aliasID.setOverlap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mUnitStatusMap.put(unitStatus, alias);
|
||||||
|
break;
|
||||||
|
case TONES:
|
||||||
|
ToneSequence toneSequence = ((TonesID)id).getToneSequence();
|
||||||
|
|
||||||
|
if(toneSequence != null)
|
||||||
|
{
|
||||||
|
if(mToneSequenceMap.containsKey(toneSequence))
|
||||||
|
{
|
||||||
|
id.setOverlap(true);
|
||||||
|
|
||||||
|
Alias existing = mToneSequenceMap.get(toneSequence);
|
||||||
|
|
||||||
|
for(AliasID aliasID: existing.getAliasIdentifiers())
|
||||||
|
{
|
||||||
|
if(aliasID instanceof TonesID && ((TonesID)aliasID).equals(id))
|
||||||
|
{
|
||||||
|
aliasID.setOverlap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mToneSequenceMap.put(toneSequence, alias);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,18 +253,112 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
* Removes the alias from this list
|
||||||
*/
|
*/
|
||||||
public void removeAlias(Alias alias)
|
public void removeAlias(Alias alias)
|
||||||
{
|
{
|
||||||
for(TalkgroupAliasList talkgroupAliasList: mTalkgroupProtocolMap.values())
|
for(AliasID aliasID: alias.getAliasIdentifiers())
|
||||||
{
|
{
|
||||||
talkgroupAliasList.remove(alias);
|
removeAliasID(aliasID, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
remove(alias, mStatusMap);
|
mAliases.remove(alias);
|
||||||
remove(alias, mESNMap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -241,20 +414,13 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
switch(event.getEvent())
|
switch(event.getEvent())
|
||||||
{
|
{
|
||||||
case ADD:
|
case ADD:
|
||||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
if(alias.getAliasListName() != null && getName().equalsIgnoreCase(alias.getAliasListName()))
|
||||||
{
|
{
|
||||||
addAlias(alias);
|
addAlias(alias);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CHANGE:
|
|
||||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
|
||||||
{
|
|
||||||
removeAlias(alias);
|
|
||||||
addAlias(alias);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DELETE:
|
case DELETE:
|
||||||
if(alias.getList() != null && getName().equalsIgnoreCase(alias.getList()))
|
if(alias.getAliasListName() != null && getName().equalsIgnoreCase(alias.getAliasListName()))
|
||||||
{
|
{
|
||||||
removeAlias(alias);
|
removeAlias(alias);
|
||||||
}
|
}
|
||||||
@@ -336,14 +502,31 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
if(identifier instanceof UnitStatusIdentifier)
|
if(identifier instanceof UnitStatusIdentifier)
|
||||||
{
|
{
|
||||||
int status = ((UnitStatusIdentifier)identifier).getValue();
|
int status = ((UnitStatusIdentifier)identifier).getValue();
|
||||||
return toList(mStatusMap.get(status));
|
return toList(mUserStatusMap.get(status));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case USER_STATUS:
|
case USER_STATUS:
|
||||||
if(identifier instanceof UserStatusIdentifier)
|
if(identifier instanceof UserStatusIdentifier)
|
||||||
{
|
{
|
||||||
int status = ((UserStatusIdentifier)identifier).getValue();
|
int status = ((UserStatusIdentifier)identifier).getValue();
|
||||||
return toList(mStatusMap.get(status));
|
return toList(mUserStatusMap.get(status));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case TONE:
|
||||||
|
if(identifier instanceof ToneIdentifier)
|
||||||
|
{
|
||||||
|
ToneSequence toneSequence = ((ToneIdentifier)identifier).getValue();
|
||||||
|
|
||||||
|
if(toneSequence != null && toneSequence.hasTones())
|
||||||
|
{
|
||||||
|
for(Map.Entry<ToneSequence,Alias> entry: mToneSequenceMap.entrySet())
|
||||||
|
{
|
||||||
|
if(entry.getKey().isContainedIn(toneSequence))
|
||||||
|
{
|
||||||
|
return toList(entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -477,13 +660,32 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the alias (as a value) from the specified map
|
* 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 static void remove(Alias alias, Map map)
|
public List<Alias> getOverlappingAliases(Alias alias, AliasID aliasID)
|
||||||
{
|
{
|
||||||
map.entrySet().removeIf(entry -> alias.equals(((Map.Entry)entry).getValue()));
|
List<Alias> 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
|
* Listing of talkgroups and ranges for a specific protocol
|
||||||
@@ -520,16 +722,22 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
|
|
||||||
public void add(Talkgroup talkgroup, Alias alias)
|
public void add(Talkgroup talkgroup, Alias alias)
|
||||||
{
|
{
|
||||||
//Detect talkgroup collisions
|
//Detect talkgroup collisions and set overlap flag for both
|
||||||
if(mTalkgroupAliasMap.containsKey(talkgroup.getValue()))
|
if(mTalkgroupAliasMap.containsKey(talkgroup.getValue()))
|
||||||
{
|
{
|
||||||
Alias existing = mTalkgroupAliasMap.get(talkgroup.getValue());
|
Alias existing = mTalkgroupAliasMap.get(talkgroup.getValue());
|
||||||
|
|
||||||
if(!existing.equals(alias))
|
if(!existing.equals(alias))
|
||||||
{
|
{
|
||||||
mLog.warn("Alias [" + alias.getName() + "] talkgroup [" + talkgroup.getValue() +
|
talkgroup.setOverlap(true);
|
||||||
"] has the same talkgroup value as alias [" + existing.getName() +
|
|
||||||
"] - alias [" + alias.getName() + "] will be used for alias list [" + getName() + "]");
|
for(AliasID aliasID: existing.getAliasIdentifiers())
|
||||||
|
{
|
||||||
|
if(aliasID instanceof Talkgroup && ((Talkgroup)aliasID).getValue() == talkgroup.getValue())
|
||||||
|
{
|
||||||
|
aliasID.setOverlap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,32 +751,29 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
{
|
{
|
||||||
if(talkgroupRange.overlaps(entry.getKey()) && !entry.getValue().equals(alias))
|
if(talkgroupRange.overlaps(entry.getKey()) && !entry.getValue().equals(alias))
|
||||||
{
|
{
|
||||||
mLog.warn("Alias [" + alias.getName() + "] with talkgroup range [" + talkgroupRange.toString() +
|
talkgroupRange.setOverlap(true);
|
||||||
"] overlaps with alias [" + entry.getValue().getName() +
|
entry.getKey().setOverlap(true);
|
||||||
"] with talkgroup range [" + entry.getKey().toString() + "] for alias list [" + getName() + "]");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mTalkgroupRangeAliasMap.put(talkgroupRange, alias);
|
mTalkgroupRangeAliasMap.put(talkgroupRange, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Talkgroup talkgroup)
|
public void remove(Talkgroup talkgroup, Alias alias)
|
||||||
{
|
{
|
||||||
mTalkgroupAliasMap.remove(talkgroup.getValue());
|
if(mTalkgroupAliasMap.containsKey(talkgroup.getValue()) && mTalkgroupAliasMap.get(talkgroup.getValue()) == alias)
|
||||||
|
{
|
||||||
|
mTalkgroupAliasMap.remove(talkgroup.getValue());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(TalkgroupRange talkgroupRange)
|
public void remove(TalkgroupRange talkgroupRange, Alias alias)
|
||||||
{
|
{
|
||||||
mTalkgroupRangeAliasMap.remove(talkgroupRange);
|
//Only remove the entry if both the key and the value match
|
||||||
}
|
if(mTalkgroupRangeAliasMap.containsKey(talkgroupRange) && mTalkgroupRangeAliasMap.get(talkgroupRange) == alias)
|
||||||
|
{
|
||||||
/**
|
mTalkgroupRangeAliasMap.remove(talkgroupRange);
|
||||||
* Removes the alias from all internal maps
|
}
|
||||||
*/
|
|
||||||
public void remove(Alias alias)
|
|
||||||
{
|
|
||||||
AliasList.remove(alias, mTalkgroupAliasMap);
|
|
||||||
AliasList.remove(alias, mTalkgroupRangeAliasMap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -614,9 +819,15 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
|
|
||||||
if(!existing.equals(alias))
|
if(!existing.equals(alias))
|
||||||
{
|
{
|
||||||
mLog.warn("Alias [" + alias.getName() + "] radio ID [" + radio.getValue() +
|
radio.setOverlap(true);
|
||||||
"] has the same value as alias [" + existing.getName() +
|
|
||||||
"] - alias [" + alias.getName() + "] will be used for alias list [" + getName() + "]");
|
for(AliasID aliasID: existing.getAliasIdentifiers())
|
||||||
|
{
|
||||||
|
if(aliasID instanceof Radio && ((Radio)aliasID).getValue() == radio.getValue())
|
||||||
|
{
|
||||||
|
aliasID.setOverlap(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -630,32 +841,30 @@ public class AliasList implements Listener<AliasEvent>
|
|||||||
{
|
{
|
||||||
if(radioRange.overlaps(entry.getKey()) && !entry.getValue().equals(alias))
|
if(radioRange.overlaps(entry.getKey()) && !entry.getValue().equals(alias))
|
||||||
{
|
{
|
||||||
mLog.warn("Alias [" + alias.getName() + "] with radio ID range [" + radioRange.toString() +
|
radioRange.setOverlap(true);
|
||||||
"] overlaps with alias [" + entry.getValue().getName() +
|
entry.getKey().setOverlap(true);
|
||||||
"] with range [" + entry.getKey().toString() + "] for alias list [" + getName() + "]");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mRadioRangeAliasMap.put(radioRange, alias);
|
mRadioRangeAliasMap.put(radioRange, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void remove(Radio radio)
|
public void remove(Radio radio, Alias alias)
|
||||||
{
|
{
|
||||||
mRadioAliasMap.remove(radio.getValue());
|
//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)
|
public void remove(RadioRange radioRange, Alias alias)
|
||||||
{
|
{
|
||||||
mRadioRangeAliasMap.remove(radioRange);
|
//Only remove the entry if both the key and the value match
|
||||||
}
|
if(mRadioRangeAliasMap.containsKey(radioRange) && mRadioRangeAliasMap.get(radioRange) == alias)
|
||||||
|
{
|
||||||
/**
|
mRadioRangeAliasMap.remove(radioRange);
|
||||||
* Removes the alias from all internal maps
|
}
|
||||||
*/
|
|
||||||
public void remove(Alias alias)
|
|
||||||
{
|
|
||||||
AliasList.remove(alias, mRadioAliasMap);
|
|
||||||
AliasList.remove(alias, mRadioRangeAliasMap);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,59 +1,73 @@
|
|||||||
/*
|
/*
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
*/
|
||||||
package io.github.dsheirer.alias;
|
package io.github.dsheirer.alias;
|
||||||
|
|
||||||
|
import io.github.dsheirer.alias.id.AliasID;
|
||||||
|
import io.github.dsheirer.alias.id.AliasIDType;
|
||||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
||||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||||
import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier;
|
import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier;
|
||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias Model contains all aliases and is responsible for creation and management of alias lists. Alias lists are a
|
* Alias Model contains all aliases and is responsible for creation and management of alias lists. Alias lists are a
|
||||||
* set of aliases that all share a common alias list name and can be attached to a decoding channel for aliasing
|
* set of aliases that all share a common alias list name and can be attached to a decoding channel for aliasing
|
||||||
* identifiers produced by channel decoder(s).
|
* identifiers produced by channel decoder(s).
|
||||||
*/
|
*/
|
||||||
public class AliasModel extends AbstractTableModel
|
public class AliasModel
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private final static Logger mLog = LoggerFactory.getLogger(AliasModel.class);
|
||||||
|
public static final String NO_ALIAS_LIST = "(No Alias List)";
|
||||||
public static final int COLUMN_LIST = 0;
|
private ObservableList<Alias> mAliases = FXCollections.observableArrayList(Alias.extractor());
|
||||||
public static final int COLUMN_GROUP = 1;
|
private ObservableList<String> mAliasListNames = FXCollections.observableArrayList();
|
||||||
public static final int COLUMN_NAME = 2;
|
|
||||||
public static final int COLUMN_ICON = 3;
|
|
||||||
public static final int COLUMN_COLOR = 4;
|
|
||||||
|
|
||||||
private List<Alias> mAliases = new CopyOnWriteArrayList<>();
|
|
||||||
private Broadcaster<AliasEvent> mAliasEventBroadcaster = new Broadcaster<>();
|
private Broadcaster<AliasEvent> mAliasEventBroadcaster = new Broadcaster<>();
|
||||||
private Map<String,AliasList> mAliasListMap = new HashMap<>();
|
private Map<String,AliasList> mAliasListMap = new HashMap<>();
|
||||||
|
|
||||||
public AliasModel()
|
public AliasModel()
|
||||||
{
|
{
|
||||||
|
//Register a listener to detect alias changes and broadcast change events to cause playlist save requests
|
||||||
|
mAliases.addListener(new AliasListChangeListener());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableList<Alias> aliasList()
|
||||||
|
{
|
||||||
|
return mAliases;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableList<String> aliasListNames()
|
||||||
|
{
|
||||||
|
return mAliasListNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,14 +78,17 @@ public class AliasModel extends AbstractTableModel
|
|||||||
return Collections.unmodifiableList(mAliases);
|
return Collections.unmodifiableList(mAliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Alias getAliasAtIndex(int row)
|
/**
|
||||||
|
* Removes all aliases from the list and broadcasts the alias delete event for each
|
||||||
|
*/
|
||||||
|
public void clear()
|
||||||
{
|
{
|
||||||
if(mAliases.size() >= row)
|
List<Alias> aliasToRemove = new ArrayList<>(mAliases);
|
||||||
{
|
|
||||||
return mAliases.get(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
for(Alias alias: aliasToRemove)
|
||||||
|
{
|
||||||
|
removeAlias(alias);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -126,7 +143,7 @@ public class AliasModel extends AbstractTableModel
|
|||||||
|
|
||||||
for(Alias alias : mAliases)
|
for(Alias alias : mAliases)
|
||||||
{
|
{
|
||||||
if(alias.hasList() && alias.getList().equalsIgnoreCase(name))
|
if(alias.hasList() && alias.getAliasListName().equalsIgnoreCase(name))
|
||||||
{
|
{
|
||||||
aliasList.addAlias(alias);
|
aliasList.addAlias(alias);
|
||||||
}
|
}
|
||||||
@@ -145,19 +162,7 @@ public class AliasModel extends AbstractTableModel
|
|||||||
*/
|
*/
|
||||||
public List<String> getListNames()
|
public List<String> getListNames()
|
||||||
{
|
{
|
||||||
List<String> listNames = new ArrayList<>();
|
return mAliasListNames;
|
||||||
|
|
||||||
for(Alias alias : mAliases)
|
|
||||||
{
|
|
||||||
if(alias.hasList() && !listNames.contains(alias.getList()))
|
|
||||||
{
|
|
||||||
listNames.add(alias.getList());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(listNames);
|
|
||||||
|
|
||||||
return listNames;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,33 +185,6 @@ public class AliasModel extends AbstractTableModel
|
|||||||
return groupNames;
|
return groupNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of alias group names for all aliases that have a matching
|
|
||||||
* list name value
|
|
||||||
*/
|
|
||||||
public List<String> getGroupNames(String listName)
|
|
||||||
{
|
|
||||||
List<String> 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
|
* Bulk loading of aliases
|
||||||
*/
|
*/
|
||||||
@@ -226,19 +204,33 @@ public class AliasModel extends AbstractTableModel
|
|||||||
if(alias != null)
|
if(alias != null)
|
||||||
{
|
{
|
||||||
mAliases.add(alias);
|
mAliases.add(alias);
|
||||||
|
addAliasList(alias.getAliasListName());
|
||||||
int index = mAliases.size() - 1;
|
int index = mAliases.size() - 1;
|
||||||
|
|
||||||
fireTableRowsInserted(index, index);
|
|
||||||
|
|
||||||
broadcast(new AliasEvent(alias, AliasEvent.Event.ADD));
|
broadcast(new AliasEvent(alias, AliasEvent.Event.ADD));
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addAliasList(String aliasListName)
|
||||||
|
{
|
||||||
|
if(aliasListName != null && !aliasListName.isEmpty())
|
||||||
|
{
|
||||||
|
if(!mAliasListNames.contains(aliasListName))
|
||||||
|
{
|
||||||
|
mAliasListNames.add(aliasListName);
|
||||||
|
FXCollections.sort(mAliasListNames);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(!mAliasListNames.contains(NO_ALIAS_LIST))
|
||||||
|
{
|
||||||
|
//This list allows users to view unassigned aliases so that they can move them to a valid alias list, but
|
||||||
|
// it is not assignable to a channel
|
||||||
|
mAliasListNames.add(NO_ALIAS_LIST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the channel from the model and broadcasts a channel remove event
|
* Removes the channel from the model and broadcasts a channel remove event
|
||||||
*/
|
*/
|
||||||
@@ -246,119 +238,94 @@ public class AliasModel extends AbstractTableModel
|
|||||||
{
|
{
|
||||||
if(alias != null)
|
if(alias != null)
|
||||||
{
|
{
|
||||||
int index = mAliases.indexOf(alias);
|
|
||||||
|
|
||||||
mAliases.remove(alias);
|
mAliases.remove(alias);
|
||||||
|
|
||||||
fireTableRowsDeleted(index, index);
|
|
||||||
|
|
||||||
broadcast(new AliasEvent(alias, AliasEvent.Event.DELETE));
|
broadcast(new AliasEvent(alias, AliasEvent.Event.DELETE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renames any broadcast channels that have the previous name.
|
* Retrieves all aliases that match the alias list and have at least one alias ID of the specified type
|
||||||
*
|
* @param aliasListName to search
|
||||||
* @param previousName to rename
|
* @param type to find
|
||||||
* @param newName to assign to the broadcast channel
|
* @return list of aliases
|
||||||
*/
|
*/
|
||||||
public void renameBroadcastChannel(String previousName, String newName)
|
public List<Alias> getAliases(String aliasListName, AliasIDType type)
|
||||||
{
|
{
|
||||||
if(previousName == null || previousName.isEmpty() || newName == null || newName.isEmpty())
|
List<Alias> aliases = new ArrayList<>();
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(Alias alias : mAliases)
|
for(Alias alias : mAliases)
|
||||||
{
|
{
|
||||||
if(alias.hasBroadcastChannel(previousName))
|
if(alias.hasList() && alias.getAliasListName().equalsIgnoreCase(aliasListName))
|
||||||
{
|
{
|
||||||
for(BroadcastChannel broadcastChannel : alias.getBroadcastChannels())
|
for(AliasID aliasID: alias.getAliasIdentifiers())
|
||||||
{
|
{
|
||||||
if(broadcastChannel.getChannelName().contentEquals(previousName))
|
if(aliasID.getType() == type)
|
||||||
{
|
{
|
||||||
broadcastChannel.setChannelName(newName);
|
aliases.add(alias);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public int getRowCount()
|
* Indicates that one or more of the aliases managed by this model are configured to stream to the specified
|
||||||
|
* broadcast channel argument.
|
||||||
|
* @param broadcastChannel to check
|
||||||
|
* @return true if the broadcast channel is non-null, non-empty and at least one alias is configured to stream to
|
||||||
|
* the specified stream name.
|
||||||
|
*/
|
||||||
|
public boolean hasAliasesWithBroadcastChannel(String broadcastChannel)
|
||||||
{
|
{
|
||||||
return mAliases.size();
|
if(broadcastChannel == null || broadcastChannel.isEmpty())
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnCount()
|
|
||||||
{
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName(int columnIndex)
|
|
||||||
{
|
|
||||||
switch(columnIndex)
|
|
||||||
{
|
{
|
||||||
case COLUMN_LIST:
|
return false;
|
||||||
return "List";
|
|
||||||
case COLUMN_GROUP:
|
|
||||||
return "Group";
|
|
||||||
case COLUMN_NAME:
|
|
||||||
return "Name";
|
|
||||||
case COLUMN_ICON:
|
|
||||||
return "Icon";
|
|
||||||
case COLUMN_COLOR:
|
|
||||||
return "Color";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
for(Alias alias: mAliases)
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class<?> getColumnClass(int columnIndex)
|
|
||||||
{
|
|
||||||
if(columnIndex == COLUMN_COLOR)
|
|
||||||
{
|
{
|
||||||
return Integer.class;
|
if(alias.hasBroadcastChannel(broadcastChannel))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return String.class;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex)
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public Object getValueAt(int rowIndex, int columnIndex)
|
* Updates all aliases configured to stream to the previousStreamName with the updatedStreamName
|
||||||
|
* @param previousStreamName to be removed
|
||||||
|
* @param updatedStreamName to be added
|
||||||
|
*/
|
||||||
|
public void updateBroadcastChannel(String previousStreamName, String updatedStreamName)
|
||||||
{
|
{
|
||||||
Alias alias = mAliases.get(rowIndex);
|
if(previousStreamName == null || previousStreamName.isEmpty() || updatedStreamName == null || updatedStreamName.isEmpty())
|
||||||
|
|
||||||
switch(columnIndex)
|
|
||||||
{
|
{
|
||||||
case COLUMN_LIST:
|
return;
|
||||||
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;
|
for(Alias alias: mAliases)
|
||||||
}
|
{
|
||||||
|
if(alias.hasBroadcastChannel(previousStreamName))
|
||||||
|
{
|
||||||
|
for(BroadcastChannel broadcastChannel: alias.getBroadcastChannels())
|
||||||
|
{
|
||||||
|
if(broadcastChannel.getChannelName().contentEquals(previousStreamName))
|
||||||
|
{
|
||||||
|
alias.removeAliasID(broadcastChannel);
|
||||||
|
|
||||||
@Override
|
if(!alias.hasBroadcastChannel(updatedStreamName))
|
||||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex)
|
{
|
||||||
{
|
alias.addAliasID(new BroadcastChannel(updatedStreamName));
|
||||||
throw new IllegalArgumentException("Not yet implemented");
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void broadcast(AliasEvent event)
|
public void broadcast(AliasEvent event)
|
||||||
@@ -371,13 +338,6 @@ public class AliasModel extends AbstractTableModel
|
|||||||
alias.validate();
|
alias.validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(event.getEvent() == AliasEvent.Event.CHANGE)
|
|
||||||
{
|
|
||||||
int index = mAliases.indexOf(event.getAlias());
|
|
||||||
|
|
||||||
fireTableRowsUpdated(index, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
mAliasEventBroadcaster.broadcast(event);
|
mAliasEventBroadcaster.broadcast(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,4 +350,40 @@ public class AliasModel extends AbstractTableModel
|
|||||||
{
|
{
|
||||||
mAliasEventBroadcaster.removeListener(listener);
|
mAliasEventBroadcaster.removeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable list change listener for both channels and traffic channels lists
|
||||||
|
*/
|
||||||
|
public class AliasListChangeListener implements ListChangeListener<Alias>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onChanged(ListChangeListener.Change<? extends Alias> change)
|
||||||
|
{
|
||||||
|
while(change.next())
|
||||||
|
{
|
||||||
|
if(change.wasAdded())
|
||||||
|
{
|
||||||
|
for(Alias alias: change.getAddedSubList())
|
||||||
|
{
|
||||||
|
mAliasEventBroadcaster.broadcast(new AliasEvent(alias, AliasEvent.Event.ADD));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,333 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias;
|
|
||||||
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.icon.Icon;
|
|
||||||
import io.github.dsheirer.icon.IconListCellRenderer;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import io.github.dsheirer.icon.IconTableModel;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.DocumentEvent;
|
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
import javax.swing.event.TableModelEvent;
|
|
||||||
import javax.swing.event.TableModelListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AliasNameEditor extends Editor<Alias>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static ComboBoxModel<String> EMPTY_LIST_MODEL = new DefaultComboBoxModel<>();
|
|
||||||
private static ComboBoxModel<String> EMPTY_GROUP_MODEL = new DefaultComboBoxModel<>();
|
|
||||||
|
|
||||||
private JComboBox<String> mListCombo = new JComboBox<>(EMPTY_LIST_MODEL);
|
|
||||||
private JComboBox<String> mGroupCombo = new JComboBox<>(EMPTY_GROUP_MODEL);
|
|
||||||
private JComboBox<Icon> mIconCombo;
|
|
||||||
private JTextField mName;
|
|
||||||
private JButton mButtonColor;
|
|
||||||
private JButton mBtnIconManager;
|
|
||||||
|
|
||||||
private AliasModel mAliasModel;
|
|
||||||
private IconManager mIconManager;
|
|
||||||
|
|
||||||
public AliasNameEditor(AliasModel aliasModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
mAliasModel = aliasModel;
|
|
||||||
mIconManager = iconManager;
|
|
||||||
|
|
||||||
mIconManager.getModel().addTableModelListener(new TableModelListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void tableChanged(TableModelEvent e)
|
|
||||||
{
|
|
||||||
refreshIcons();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[right][grow,fill]", "[][][][][][][grow]"));
|
|
||||||
|
|
||||||
add(new JLabel("Name:"));
|
|
||||||
mName = new JTextField();
|
|
||||||
mName.getDocument().addDocumentListener(new DocumentListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void removeUpdate(DocumentEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertUpdate(DocumentEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(DocumentEvent e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mName, "wrap");
|
|
||||||
|
|
||||||
add(new JLabel("List:"));
|
|
||||||
mListCombo.setEditable(true);
|
|
||||||
mListCombo.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
if(mListCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
List<String> groups = mAliasModel
|
|
||||||
.getGroupNames((String) mListCombo.getSelectedItem());
|
|
||||||
|
|
||||||
if(groups.isEmpty())
|
|
||||||
{
|
|
||||||
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
|
|
||||||
groups.toArray(new String[0])));
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mListCombo, "wrap");
|
|
||||||
|
|
||||||
add(new JLabel("Group:"));
|
|
||||||
mGroupCombo.setEditable(true);
|
|
||||||
mGroupCombo.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mGroupCombo, "wrap");
|
|
||||||
|
|
||||||
add(new JLabel("Color:"));
|
|
||||||
|
|
||||||
mButtonColor = new JButton("Select ...");
|
|
||||||
mButtonColor.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
Color newColor = JColorChooser.showDialog(
|
|
||||||
AliasNameEditor.this,
|
|
||||||
"Choose color for this alias",
|
|
||||||
(hasItem() ? getItem().getDisplayColor() : null));
|
|
||||||
|
|
||||||
if(newColor != null)
|
|
||||||
{
|
|
||||||
mButtonColor.setForeground(newColor);
|
|
||||||
mButtonColor.setBackground(newColor);
|
|
||||||
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mButtonColor, "wrap");
|
|
||||||
|
|
||||||
add(new JLabel("Icon:"));
|
|
||||||
|
|
||||||
mIconCombo = new JComboBox<Icon>(mIconManager.getIcons());
|
|
||||||
|
|
||||||
IconListCellRenderer renderer = new IconListCellRenderer(mIconManager);
|
|
||||||
renderer.setPreferredSize(new Dimension(200, 30));
|
|
||||||
mIconCombo.setRenderer(renderer);
|
|
||||||
mIconCombo.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mIconCombo, "wrap");
|
|
||||||
|
|
||||||
//Dummy place holder
|
|
||||||
add(new JLabel());
|
|
||||||
|
|
||||||
mBtnIconManager = new JButton("Icon Manager");
|
|
||||||
mBtnIconManager.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent arg0)
|
|
||||||
{
|
|
||||||
mIconManager.showEditor(AliasNameEditor.this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mBtnIconManager, "span 2,wrap");
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshIcons()
|
|
||||||
{
|
|
||||||
if(mIconCombo != null)
|
|
||||||
{
|
|
||||||
EventQueue.invokeLater(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
String iconName = getItem().getIconName();
|
|
||||||
Icon aliasIcon = mIconManager.getModel().getIcon(iconName);
|
|
||||||
|
|
||||||
if(aliasIcon != null)
|
|
||||||
{
|
|
||||||
mIconCombo.setSelectedItem(aliasIcon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(Alias alias)
|
|
||||||
{
|
|
||||||
super.setItem(alias);
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
mName.setText(alias.getName());
|
|
||||||
|
|
||||||
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
|
|
||||||
|
|
||||||
List<String> listNames = mAliasModel.getListNames();
|
|
||||||
|
|
||||||
if(listNames.isEmpty())
|
|
||||||
{
|
|
||||||
mListCombo.setModel(EMPTY_LIST_MODEL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mListCombo.setModel(new DefaultComboBoxModel<String>(
|
|
||||||
listNames.toArray(new String[0])));
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
mListCombo.setSelectedItem(alias.getList());
|
|
||||||
|
|
||||||
List<String> groupNames = mAliasModel.getGroupNames(alias.getList());
|
|
||||||
|
|
||||||
if(groupNames.isEmpty())
|
|
||||||
{
|
|
||||||
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
|
|
||||||
groupNames.toArray(new String[0])));
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
mGroupCombo.setSelectedItem(alias.getGroup());
|
|
||||||
|
|
||||||
Color color = alias.getDisplayColor();
|
|
||||||
|
|
||||||
mButtonColor.setBackground(color);
|
|
||||||
mButtonColor.setForeground(color);
|
|
||||||
|
|
||||||
String iconName = alias.getIconName();
|
|
||||||
|
|
||||||
if(iconName == null)
|
|
||||||
{
|
|
||||||
iconName = IconTableModel.DEFAULT_ICON;
|
|
||||||
}
|
|
||||||
|
|
||||||
Icon savedIcon = mIconManager.getModel().getIcon(iconName);
|
|
||||||
|
|
||||||
if(savedIcon != null)
|
|
||||||
{
|
|
||||||
mIconCombo.setSelectedItem(savedIcon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mListCombo.setModel(EMPTY_LIST_MODEL);
|
|
||||||
mGroupCombo.setModel(EMPTY_GROUP_MODEL);
|
|
||||||
mName.setText(null);
|
|
||||||
|
|
||||||
mButtonColor.setBackground(getBackground());
|
|
||||||
mButtonColor.setForeground(getForeground());
|
|
||||||
}
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if(hasItem() && isModified())
|
|
||||||
{
|
|
||||||
Alias alias = getItem();
|
|
||||||
|
|
||||||
if(mListCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
alias.setList((String) mListCombo.getSelectedItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mGroupCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
alias.setGroup((String) mGroupCombo.getSelectedItem());
|
|
||||||
}
|
|
||||||
|
|
||||||
alias.setName(mName.getText());
|
|
||||||
|
|
||||||
alias.setColor(mButtonColor.getBackground().getRGB());
|
|
||||||
|
|
||||||
if(mIconCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
alias.setIconName(((Icon) mIconCombo.getSelectedItem()).getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
//Broadcast an alias change event to save the updates
|
|
||||||
mAliasModel.broadcast(new AliasEvent(getItem(), AliasEvent.Event.CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,121 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
|
|
||||||
public abstract class ComponentEditor<T> extends JPanel implements DocumentListener
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private boolean mModified;
|
|
||||||
private ComponentModificationListener mListener;
|
|
||||||
protected T mComponent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract class for editor with notifications when contents are modified
|
|
||||||
* and methods for saving or resetting the component values with the
|
|
||||||
* contents of the editor.
|
|
||||||
*/
|
|
||||||
public ComponentEditor( T component )
|
|
||||||
{
|
|
||||||
mComponent = component;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ComponentEditor()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void dispose()
|
|
||||||
{
|
|
||||||
mComponent = null;
|
|
||||||
mListener = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getComponent()
|
|
||||||
{
|
|
||||||
return mComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setModified( boolean modified )
|
|
||||||
{
|
|
||||||
mModified = modified;
|
|
||||||
|
|
||||||
if( modified && mListener != null )
|
|
||||||
{
|
|
||||||
mListener.componentModified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if the contents of the editor have been modified
|
|
||||||
*/
|
|
||||||
public boolean isModified()
|
|
||||||
{
|
|
||||||
return mModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setComponentModificationListener( ComponentModificationListener listener )
|
|
||||||
{
|
|
||||||
mListener = listener;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets or resets the editable component
|
|
||||||
*/
|
|
||||||
public abstract void setComponent( T t );
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves changed editor values to the component
|
|
||||||
*/
|
|
||||||
public abstract void save();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reloads the editor contents from the source component and resets the
|
|
||||||
* modified flag
|
|
||||||
*/
|
|
||||||
public void reset()
|
|
||||||
{
|
|
||||||
setComponent( getComponent() );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate contents of other editors against this component editor before
|
|
||||||
* saving. Override this method to allow controller to pass other editors
|
|
||||||
* to this editor for content inspection/validation before indicating that
|
|
||||||
* this editor passes validation. This allows for validating editor contents
|
|
||||||
* that are contingent on settings in other editors.
|
|
||||||
*
|
|
||||||
* @throws ComponentValidationException if the contents of the editor
|
|
||||||
* argument cannot be validated, with the exception containing a detailed
|
|
||||||
* description of the issue.
|
|
||||||
*/
|
|
||||||
public void validate( ComponentEditor<?> editor ) throws ComponentValidationException
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listener interface to receive notification that the contents of the
|
|
||||||
* editor have been modified from the original component value and either
|
|
||||||
* need to be saved or reset
|
|
||||||
*/
|
|
||||||
public interface ComponentModificationListener
|
|
||||||
{
|
|
||||||
public void componentModified();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
package io.github.dsheirer.alias;
|
|
||||||
|
|
||||||
public class ComponentValidationException extends Exception
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Component editor contents validation error
|
|
||||||
*/
|
|
||||||
public ComponentValidationException( String message )
|
|
||||||
{
|
|
||||||
super( message );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,466 +0,0 @@
|
|||||||
package io.github.dsheirer.alias;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasIDType;
|
|
||||||
import io.github.dsheirer.alias.id.broadcast.BroadcastChannel;
|
|
||||||
import io.github.dsheirer.alias.id.priority.Priority;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.icon.Icon;
|
|
||||||
import io.github.dsheirer.icon.IconListCellRenderer;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import javax.swing.event.TableModelEvent;
|
|
||||||
import javax.swing.event.TableModelListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class MultipleAliasEditor extends Editor<List<Alias>>
|
|
||||||
implements Listener<AliasEvent>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(MultipleAliasEditor.class);
|
|
||||||
|
|
||||||
private static String HELP_TEXT =
|
|
||||||
"<html>Select attributes below to change for all selected aliases</html>";
|
|
||||||
|
|
||||||
private JLabel mAliasCountLabel;
|
|
||||||
private JLabel mAliasCount;
|
|
||||||
|
|
||||||
private JCheckBox mListCheckBox = new JCheckBox("List");
|
|
||||||
private JComboBox<String> mListCombo = new JComboBox<>();
|
|
||||||
private JCheckBox mGroupCheckBox = new JCheckBox("Group");
|
|
||||||
private JComboBox<String> mGroupCombo = new JComboBox<>();
|
|
||||||
private JCheckBox mIconCheckBox = new JCheckBox("Icon");
|
|
||||||
private JComboBox<Icon> mIconCombo;
|
|
||||||
private JCheckBox mColorCheckBox = new JCheckBox("Color");
|
|
||||||
private JButton mButtonColor;
|
|
||||||
private JButton mBtnIconManager;
|
|
||||||
private JCheckBox mRecordCheckBox = new JCheckBox("Record");
|
|
||||||
private JComboBox<Record> mRecordActionCombo = new JComboBox<>(Record.values());
|
|
||||||
private JCheckBox mPriorityCheckBox = new JCheckBox("Priority");
|
|
||||||
private JSlider mPrioritySlider;
|
|
||||||
private JLabel mPrioritySliderLabel;
|
|
||||||
private JCheckBox mStreamCheckBox = new JCheckBox("Stream");
|
|
||||||
private JComboBox<String> mStreamCombo;
|
|
||||||
|
|
||||||
private AliasModel mAliasModel;
|
|
||||||
private BroadcastModel mBroadcastModel;
|
|
||||||
private IconManager mIconManager;
|
|
||||||
|
|
||||||
public MultipleAliasEditor(AliasModel aliasModel, BroadcastModel broadcastModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
mAliasModel = aliasModel;
|
|
||||||
mBroadcastModel = broadcastModel;
|
|
||||||
mIconManager = iconManager;
|
|
||||||
|
|
||||||
mAliasModel.addListener(this);
|
|
||||||
mIconManager.getModel().addTableModelListener(new TableModelListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void tableChanged(TableModelEvent e)
|
|
||||||
{
|
|
||||||
refreshIcons();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Alias> getAliases()
|
|
||||||
{
|
|
||||||
if (hasItem())
|
|
||||||
{
|
|
||||||
return (List<Alias>) getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[grow,fill][grow,fill]",
|
|
||||||
"[][][][][][][][][][][][][][grow,fill]"));
|
|
||||||
|
|
||||||
mAliasCountLabel = new JLabel("Alias:");
|
|
||||||
add(mAliasCountLabel);
|
|
||||||
|
|
||||||
mAliasCount = new JLabel("Multiple");
|
|
||||||
add(mAliasCount, "span");
|
|
||||||
|
|
||||||
add(new JSeparator(), "span");
|
|
||||||
|
|
||||||
add(new JLabel(HELP_TEXT), "span");
|
|
||||||
|
|
||||||
add(mListCheckBox);
|
|
||||||
|
|
||||||
mListCombo.setEditable(true);
|
|
||||||
add(mListCombo, "wrap");
|
|
||||||
|
|
||||||
add(mGroupCheckBox);
|
|
||||||
|
|
||||||
mGroupCombo.setEditable(true);
|
|
||||||
add(mGroupCombo, "wrap");
|
|
||||||
|
|
||||||
add(mColorCheckBox);
|
|
||||||
|
|
||||||
mButtonColor = new JButton("Select ...");
|
|
||||||
mButtonColor.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
Color newColor = JColorChooser.showDialog(
|
|
||||||
MultipleAliasEditor.this,
|
|
||||||
"Choose color for this alias", null);
|
|
||||||
|
|
||||||
if (newColor != null)
|
|
||||||
{
|
|
||||||
mButtonColor.setForeground(newColor);
|
|
||||||
mButtonColor.setBackground(newColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mButtonColor, "wrap");
|
|
||||||
|
|
||||||
add(mIconCheckBox);
|
|
||||||
|
|
||||||
mIconCombo = new JComboBox<Icon>(mIconManager.getIcons());
|
|
||||||
|
|
||||||
IconListCellRenderer renderer = new IconListCellRenderer(mIconManager);
|
|
||||||
renderer.setPreferredSize(new Dimension(200, 30));
|
|
||||||
mIconCombo.setRenderer(renderer);
|
|
||||||
add(mIconCombo, "wrap");
|
|
||||||
|
|
||||||
//Dummy place holder
|
|
||||||
add(new JLabel());
|
|
||||||
|
|
||||||
mBtnIconManager = new JButton("Icon Manager");
|
|
||||||
mBtnIconManager.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent arg0)
|
|
||||||
{
|
|
||||||
mIconManager.showEditor(MultipleAliasEditor.this);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mBtnIconManager, "span,wrap");
|
|
||||||
|
|
||||||
add(mRecordCheckBox);
|
|
||||||
add(mRecordActionCombo);
|
|
||||||
|
|
||||||
//Placeholder
|
|
||||||
add(new JLabel(" "));
|
|
||||||
mPrioritySliderLabel = new JLabel("Audio Priority: " + Priority.MIN_PRIORITY);
|
|
||||||
add(mPrioritySliderLabel);
|
|
||||||
|
|
||||||
add(mPriorityCheckBox);
|
|
||||||
|
|
||||||
mPrioritySlider = new JSlider(JSlider.HORIZONTAL,
|
|
||||||
Priority.MIN_PRIORITY,
|
|
||||||
Priority.MAX_PRIORITY + 1,
|
|
||||||
Priority.MIN_PRIORITY);
|
|
||||||
|
|
||||||
mPrioritySlider.setMajorTickSpacing(20);
|
|
||||||
mPrioritySlider.setMinorTickSpacing(5);
|
|
||||||
mPrioritySlider.setPaintTicks(true);
|
|
||||||
mPrioritySlider.setLabelTable(mPrioritySlider.createStandardLabels(25, 25));
|
|
||||||
mPrioritySlider.setPaintLabels(true);
|
|
||||||
mPrioritySlider.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
int priority = mPrioritySlider.getValue();
|
|
||||||
|
|
||||||
if (priority > Priority.MAX_PRIORITY)
|
|
||||||
{
|
|
||||||
mPrioritySliderLabel.setText("Audio Priority: Do Not Monitor");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mPrioritySliderLabel.setText("Audio Priority: " + mPrioritySlider.getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mPrioritySlider.setToolTipText(HELP_TEXT);
|
|
||||||
|
|
||||||
add(mPrioritySlider);
|
|
||||||
|
|
||||||
add(mStreamCheckBox);
|
|
||||||
|
|
||||||
mStreamCombo = new JComboBox<String>();
|
|
||||||
mStreamCombo.setEditable(true);
|
|
||||||
add(mStreamCombo, "wrap");
|
|
||||||
|
|
||||||
JButton saveButton = new JButton("Save");
|
|
||||||
saveButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(saveButton);
|
|
||||||
|
|
||||||
JButton resetButton = new JButton("Reset");
|
|
||||||
resetButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
reset();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(resetButton);
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshIcons()
|
|
||||||
{
|
|
||||||
if(mIconCombo != null)
|
|
||||||
{
|
|
||||||
EventQueue.invokeLater(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(List<Alias> item)
|
|
||||||
{
|
|
||||||
super.setItem(item);
|
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
sb.append("Multiple Selected [ ");
|
|
||||||
|
|
||||||
if (hasItem())
|
|
||||||
{
|
|
||||||
sb.append(String.valueOf(getAliases().size()));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.append("0");
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.append(" ]");
|
|
||||||
|
|
||||||
mAliasCount.setText(sb.toString());
|
|
||||||
|
|
||||||
List<String> listNames = mAliasModel.getListNames();
|
|
||||||
listNames.add(0, "");
|
|
||||||
mListCombo.setModel(new DefaultComboBoxModel<String>(
|
|
||||||
listNames.toArray(new String[0])));
|
|
||||||
|
|
||||||
List<String> groupNames = mAliasModel.getGroupNames();
|
|
||||||
groupNames.add(0, "");
|
|
||||||
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
|
|
||||||
groupNames.toArray(new String[0])));
|
|
||||||
|
|
||||||
List<String> streamNames = mBroadcastModel.getBroadcastConfigurationNames();
|
|
||||||
mStreamCombo.setModel(new DefaultComboBoxModel<String>(streamNames.toArray(new String[0])));
|
|
||||||
|
|
||||||
mIconCombo.setModel(new DefaultComboBoxModel<>(mIconManager.getIcons()));
|
|
||||||
|
|
||||||
setCheckBoxesUnselected();
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setCheckBoxesUnselected()
|
|
||||||
{
|
|
||||||
mListCheckBox.setSelected(false);
|
|
||||||
mGroupCheckBox.setSelected(false);
|
|
||||||
mColorCheckBox.setSelected(false);
|
|
||||||
mIconCheckBox.setSelected(false);
|
|
||||||
mRecordCheckBox.setSelected(false);
|
|
||||||
mPriorityCheckBox.setSelected(false);
|
|
||||||
mStreamCheckBox.setSelected(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void reset()
|
|
||||||
{
|
|
||||||
List<String> listNames = mAliasModel.getListNames();
|
|
||||||
listNames.add(0, "");
|
|
||||||
mListCombo.setModel(new DefaultComboBoxModel<String>(
|
|
||||||
listNames.toArray(new String[0])));
|
|
||||||
|
|
||||||
List<String> groupNames = mAliasModel.getGroupNames();
|
|
||||||
groupNames.add(0, "");
|
|
||||||
mGroupCombo.setModel(new DefaultComboBoxModel<String>(
|
|
||||||
groupNames.toArray(new String[0])));
|
|
||||||
|
|
||||||
mButtonColor.setForeground(getForeground());
|
|
||||||
mButtonColor.setBackground(getBackground());
|
|
||||||
|
|
||||||
super.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasRequestedChanges()
|
|
||||||
{
|
|
||||||
return mListCheckBox.isSelected() ||
|
|
||||||
mGroupCheckBox.isSelected() ||
|
|
||||||
mColorCheckBox.isSelected() ||
|
|
||||||
mIconCheckBox.isSelected() ||
|
|
||||||
mRecordCheckBox.isSelected() ||
|
|
||||||
mPriorityCheckBox.isSelected() ||
|
|
||||||
mStreamCheckBox.isSelected();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if (hasRequestedChanges() && hasItem())
|
|
||||||
{
|
|
||||||
List<Alias> aliases = getAliases();
|
|
||||||
|
|
||||||
for (Alias alias : aliases)
|
|
||||||
{
|
|
||||||
if (mListCheckBox.isSelected())
|
|
||||||
{
|
|
||||||
String list = null;
|
|
||||||
|
|
||||||
if (mListCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
list = (String) mListCombo.getSelectedItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
alias.setList(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mGroupCheckBox.isSelected())
|
|
||||||
{
|
|
||||||
String group = null;
|
|
||||||
|
|
||||||
if (mGroupCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
group = (String) mGroupCombo.getSelectedItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
alias.setGroup(group);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mColorCheckBox.isSelected())
|
|
||||||
{
|
|
||||||
alias.setColor(mButtonColor.getForeground().getRGB());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mIconCheckBox.isSelected())
|
|
||||||
{
|
|
||||||
if (mIconCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
alias.setIconName(((Icon)mIconCombo.getSelectedItem()).getName());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
alias.setIconName(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mRecordCheckBox.isSelected())
|
|
||||||
{
|
|
||||||
Record action =
|
|
||||||
(Record) mRecordActionCombo.getSelectedItem();
|
|
||||||
|
|
||||||
alias.setRecordable(action == Record.RECORDABLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mPriorityCheckBox.isSelected())
|
|
||||||
{
|
|
||||||
int priority = mPrioritySlider.getValue();
|
|
||||||
|
|
||||||
//This is a work-around -- we use max priority + 1 in the
|
|
||||||
//gui to indicate do not monitor, and change the value here
|
|
||||||
if (priority == Priority.MAX_PRIORITY + 1)
|
|
||||||
{
|
|
||||||
priority = Priority.DO_NOT_MONITOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
alias.setCallPriority(priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(mStreamCheckBox.isSelected())
|
|
||||||
{
|
|
||||||
if(mStreamCombo.getSelectedItem() != null)
|
|
||||||
{
|
|
||||||
String streamName = (String)mStreamCombo.getSelectedItem();
|
|
||||||
|
|
||||||
boolean hasChannel = false;
|
|
||||||
|
|
||||||
//Ensure the alias doesn't already have the channel
|
|
||||||
for(BroadcastChannel channel: alias.getBroadcastChannels())
|
|
||||||
{
|
|
||||||
if(channel.getChannelName().equals(streamName))
|
|
||||||
{
|
|
||||||
hasChannel = true;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!hasChannel)
|
|
||||||
{
|
|
||||||
BroadcastChannel channel = (BroadcastChannel)AliasFactory
|
|
||||||
.getAliasID(AliasIDType.BROADCAST_CHANNEL);
|
|
||||||
|
|
||||||
channel.setChannelName(streamName);
|
|
||||||
alias.addAliasID(channel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Alias alias : aliases)
|
|
||||||
{
|
|
||||||
//Broadcast an alias change event to save the updates
|
|
||||||
mAliasModel.broadcast(new AliasEvent(alias, AliasEvent.Event.CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive(AliasEvent event)
|
|
||||||
{
|
|
||||||
if (event.getEvent() == AliasEvent.Event.DELETE &&
|
|
||||||
hasItem() &&
|
|
||||||
getAliases().contains(event.getAlias()))
|
|
||||||
{
|
|
||||||
getAliases().remove(event.getAlias());
|
|
||||||
setItem(getAliases());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum Record
|
|
||||||
{
|
|
||||||
NON_RECORDABLE("Non-Recordable"),
|
|
||||||
RECORDABLE("Recordable");
|
|
||||||
|
|
||||||
private String mLabel;
|
|
||||||
|
|
||||||
private Record(String label)
|
|
||||||
{
|
|
||||||
mLabel = label;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return mLabel;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -27,6 +27,9 @@ import io.github.dsheirer.alias.action.beep.BeepAction;
|
|||||||
import io.github.dsheirer.alias.action.clip.ClipAction;
|
import io.github.dsheirer.alias.action.clip.ClipAction;
|
||||||
import io.github.dsheirer.alias.action.script.ScriptAction;
|
import io.github.dsheirer.alias.action.script.ScriptAction;
|
||||||
import io.github.dsheirer.message.IMessage;
|
import io.github.dsheirer.message.IMessage;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alias action defines an action to execute when an alias is detected active.
|
* Alias action defines an action to execute when an alias is detected active.
|
||||||
@@ -41,10 +44,33 @@ import io.github.dsheirer.message.IMessage;
|
|||||||
@JacksonXmlRootElement(localName = "action")
|
@JacksonXmlRootElement(localName = "action")
|
||||||
public abstract class AliasAction
|
public abstract class AliasAction
|
||||||
{
|
{
|
||||||
|
private SimpleStringProperty mValueProperty = new SimpleStringProperty();
|
||||||
|
|
||||||
public AliasAction()
|
public AliasAction()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String property representation of this alias ID
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public SimpleStringProperty valueProperty()
|
||||||
|
{
|
||||||
|
return mValueProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the value property for this alias ID. Note: this method is intended to be invoked by all subclasses
|
||||||
|
* each time that any of the subclass member variable values change.
|
||||||
|
*/
|
||||||
|
public void updateValueProperty()
|
||||||
|
{
|
||||||
|
valueProperty().set(toString());
|
||||||
|
|
||||||
|
//Hack: harmless, but the list extractor does not consistently update unless we do this.
|
||||||
|
valueProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public abstract AliasActionType getType();
|
public abstract AliasActionType getType();
|
||||||
|
|
||||||
@@ -60,4 +86,12 @@ public abstract class AliasAction
|
|||||||
* Dismiss a persistent alias action
|
* Dismiss a persistent alias action
|
||||||
*/
|
*/
|
||||||
public abstract void dismiss(boolean reset);
|
public abstract void dismiss(boolean reset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
|
||||||
|
*/
|
||||||
|
public static Callback<AliasAction,Observable[]> extractor()
|
||||||
|
{
|
||||||
|
return (AliasAction aliasAction) -> new Observable[] {aliasAction.valueProperty()};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,332 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.action;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.Alias;
|
|
||||||
import io.github.dsheirer.alias.AliasEvent;
|
|
||||||
import io.github.dsheirer.alias.AliasEvent.Event;
|
|
||||||
import io.github.dsheirer.alias.AliasFactory;
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.gui.editor.EmptyEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AliasActionEditor extends Editor<Alias>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static ListModel<AliasAction> EMPTY_MODEL = new DefaultListModel<>();
|
|
||||||
private JList<AliasAction> mAliasActionList = new JList<>( EMPTY_MODEL );
|
|
||||||
private JButton mNewActionButton;
|
|
||||||
private JButton mCloneActionButton;
|
|
||||||
private JButton mDeleteActionButton;
|
|
||||||
private EditorContainer mEditorContainer = new EditorContainer();
|
|
||||||
|
|
||||||
private AliasModel mAliasModel;
|
|
||||||
|
|
||||||
public AliasActionEditor( AliasModel model )
|
|
||||||
{
|
|
||||||
mAliasModel = model;
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 3",
|
|
||||||
"[grow,fill][grow,fill][grow,fill]", "[][grow,fill][]" ) );
|
|
||||||
|
|
||||||
mAliasActionList.setVisibleRowCount( 6 );
|
|
||||||
mAliasActionList.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
|
|
||||||
mAliasActionList.setLayoutOrientation( JList.VERTICAL );
|
|
||||||
mAliasActionList.addListSelectionListener( new ListSelectionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void valueChanged( ListSelectionEvent event )
|
|
||||||
{
|
|
||||||
if( !event.getValueIsAdjusting() )
|
|
||||||
{
|
|
||||||
JList<?> list = (JList<?>)event.getSource();
|
|
||||||
|
|
||||||
Object selectedItem = list.getSelectedValue();
|
|
||||||
|
|
||||||
if( selectedItem != null && selectedItem instanceof AliasAction )
|
|
||||||
{
|
|
||||||
AliasAction selected = (AliasAction)selectedItem;
|
|
||||||
|
|
||||||
mEditorContainer.setAliasAction( selected );
|
|
||||||
|
|
||||||
mCloneActionButton.setEnabled( true );
|
|
||||||
mDeleteActionButton.setEnabled( true );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mCloneActionButton.setEnabled( false );
|
|
||||||
mDeleteActionButton.setEnabled( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
JScrollPane scroller = new JScrollPane( mAliasActionList );
|
|
||||||
add( scroller, "span,grow" );
|
|
||||||
|
|
||||||
add( mEditorContainer, "span,grow" );
|
|
||||||
|
|
||||||
mNewActionButton = new JButton( "New ..." );
|
|
||||||
mNewActionButton.setToolTipText( "Create a new Alias Action" );
|
|
||||||
mNewActionButton.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JPopupMenu menu = new JPopupMenu();
|
|
||||||
|
|
||||||
menu.add( new AddAliasActionItem( AliasActionType.BEEP ) );
|
|
||||||
menu.add( new AddAliasActionItem( AliasActionType.CLIP ) );
|
|
||||||
menu.add( new AddAliasActionItem( AliasActionType.SCRIPT ) );
|
|
||||||
|
|
||||||
menu.show( e.getComponent(), e.getX(), e.getY() );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( mNewActionButton );
|
|
||||||
|
|
||||||
mCloneActionButton = new JButton( "Clone" );
|
|
||||||
mCloneActionButton.setToolTipText( "Create a copy of the currently selected action" );
|
|
||||||
mCloneActionButton.setEnabled( false );
|
|
||||||
mCloneActionButton.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
AliasAction selected = mAliasActionList.getSelectedValue();
|
|
||||||
|
|
||||||
if( selected != null )
|
|
||||||
{
|
|
||||||
AliasAction clone = AliasFactory.copyOf( selected );
|
|
||||||
|
|
||||||
if( clone != null )
|
|
||||||
{
|
|
||||||
addAliasActionToList( clone );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( mCloneActionButton );
|
|
||||||
|
|
||||||
mDeleteActionButton = new JButton( "Delete" );
|
|
||||||
mDeleteActionButton.setToolTipText( "Delete the currently selected action" );
|
|
||||||
mDeleteActionButton.setEnabled( false );
|
|
||||||
mDeleteActionButton.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
final AliasAction selected = mAliasActionList.getSelectedValue();
|
|
||||||
|
|
||||||
if( selected != null )
|
|
||||||
{
|
|
||||||
int choice = JOptionPane.showConfirmDialog( mDeleteActionButton,
|
|
||||||
"Do you want to delete [" + selected.toString() + "]",
|
|
||||||
"Are you sure?", JOptionPane.YES_NO_OPTION );
|
|
||||||
|
|
||||||
if( choice == JOptionPane.YES_OPTION && hasItem() )
|
|
||||||
{
|
|
||||||
Alias alias = getItem();
|
|
||||||
|
|
||||||
alias.removeAliasAction( selected );
|
|
||||||
|
|
||||||
mAliasModel.broadcast( new AliasEvent( alias, Event.CHANGE ) );
|
|
||||||
|
|
||||||
setItem( alias );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( mDeleteActionButton, "wrap" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( Alias alias )
|
|
||||||
{
|
|
||||||
super.setItem( alias );
|
|
||||||
|
|
||||||
if( alias == null || alias.getAction().isEmpty() )
|
|
||||||
{
|
|
||||||
mAliasActionList.setModel( EMPTY_MODEL );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DefaultListModel<AliasAction> model = new DefaultListModel<>();
|
|
||||||
|
|
||||||
List<AliasAction> actions = alias.getAction();
|
|
||||||
|
|
||||||
actions.sort(Comparator.comparing(Object::toString));
|
|
||||||
|
|
||||||
for( AliasAction action: actions )
|
|
||||||
{
|
|
||||||
model.addElement( action );
|
|
||||||
}
|
|
||||||
|
|
||||||
mAliasActionList.setModel( model );
|
|
||||||
}
|
|
||||||
|
|
||||||
mEditorContainer.setAliasAction( null );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if( isModified() || mEditorContainer.isModified() )
|
|
||||||
{
|
|
||||||
if( mEditorContainer.isModified() )
|
|
||||||
{
|
|
||||||
mEditorContainer.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
if( hasItem() )
|
|
||||||
{
|
|
||||||
mAliasModel.broadcast( new AliasEvent( getItem(), Event.CHANGE ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EditorContainer extends JPanel
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private Editor<AliasAction> mEditor = new EmptyEditor<>();
|
|
||||||
|
|
||||||
public EditorContainer()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "","[grow,fill]", "[grow,fill]" ) );
|
|
||||||
|
|
||||||
add( mEditor );
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isModified()
|
|
||||||
{
|
|
||||||
if( mEditor != null )
|
|
||||||
{
|
|
||||||
return mEditor.isModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if( mEditor != null )
|
|
||||||
{
|
|
||||||
mEditor.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAliasAction( AliasAction aliasAction )
|
|
||||||
{
|
|
||||||
if( mEditor != null )
|
|
||||||
{
|
|
||||||
if( mEditor.isModified() )
|
|
||||||
{
|
|
||||||
int option = JOptionPane.showConfirmDialog(
|
|
||||||
EditorContainer.this,
|
|
||||||
"Action settings have changed. Do you want to save these changes?",
|
|
||||||
"Save Changes?",
|
|
||||||
JOptionPane.YES_NO_OPTION,
|
|
||||||
JOptionPane.QUESTION_MESSAGE );
|
|
||||||
|
|
||||||
if( option == JOptionPane.YES_OPTION )
|
|
||||||
{
|
|
||||||
mEditor.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeAll();
|
|
||||||
|
|
||||||
//This will always give us an editor
|
|
||||||
mEditor = AliasFactory.getEditor( aliasAction );
|
|
||||||
|
|
||||||
add( mEditor );
|
|
||||||
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addAliasActionToList( final AliasAction action )
|
|
||||||
{
|
|
||||||
if( action != null && hasItem() )
|
|
||||||
{
|
|
||||||
final Alias alias = getItem();
|
|
||||||
|
|
||||||
alias.addAliasAction( action );
|
|
||||||
|
|
||||||
EventQueue.invokeLater( new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
setItem( alias );
|
|
||||||
|
|
||||||
mAliasActionList.setSelectedValue( action, true );
|
|
||||||
|
|
||||||
AliasActionEditor.this.setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AddAliasActionItem extends JMenuItem
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private AliasActionType mAliasActionType;
|
|
||||||
|
|
||||||
public AddAliasActionItem( AliasActionType type )
|
|
||||||
{
|
|
||||||
super( type.toString() );
|
|
||||||
|
|
||||||
mAliasActionType = type;
|
|
||||||
|
|
||||||
addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
final AliasAction action =
|
|
||||||
AliasFactory.getAliasAction( mAliasActionType );
|
|
||||||
|
|
||||||
addAliasActionToList( action );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
*/
|
||||||
package io.github.dsheirer.alias.action;
|
package io.github.dsheirer.alias.action;
|
||||||
|
|
||||||
@@ -63,7 +65,7 @@ public class AliasActionManager extends Module implements IMessageListener, List
|
|||||||
{
|
{
|
||||||
if(alias != null && alias.hasActions())
|
if(alias != null && alias.hasActions())
|
||||||
{
|
{
|
||||||
for(AliasAction action: alias.getAction())
|
for(AliasAction action: alias.getAliasActions())
|
||||||
{
|
{
|
||||||
action.execute(alias, message);
|
action.execute(alias, message);
|
||||||
}
|
}
|
||||||
@@ -76,13 +78,13 @@ public class AliasActionManager extends Module implements IMessageListener, List
|
|||||||
@Override
|
@Override
|
||||||
public void reset()
|
public void reset()
|
||||||
{
|
{
|
||||||
//No actions neeeded
|
//No actions needed
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void start()
|
public void start()
|
||||||
{
|
{
|
||||||
//No actions neeeded
|
//No actions needed
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public abstract class RecurringAction extends AliasAction
|
|||||||
break;
|
break;
|
||||||
case UNTIL_DISMISSED:
|
case UNTIL_DISMISSED:
|
||||||
mPerpetualAction = ThreadPool.SCHEDULED.scheduleAtFixedRate(
|
mPerpetualAction = ThreadPool.SCHEDULED.scheduleAtFixedRate(
|
||||||
new PerformActionTask(alias, message), mPeriod, mPeriod, TimeUnit.SECONDS);
|
new PerformActionTask(alias, message), 0, mPeriod, TimeUnit.SECONDS);
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append("<html><div width='250'>Alias [");
|
sb.append("<html><div width='250'>Alias [");
|
||||||
@@ -120,6 +120,7 @@ public abstract class RecurringAction extends AliasAction
|
|||||||
public void setPeriod(int period)
|
public void setPeriod(int period)
|
||||||
{
|
{
|
||||||
mPeriod = period;
|
mPeriod = period;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "interval")
|
@JacksonXmlProperty(isAttribute = true, localName = "interval")
|
||||||
@@ -131,14 +132,14 @@ public abstract class RecurringAction extends AliasAction
|
|||||||
public void setInterval(Interval interval)
|
public void setInterval(Interval interval)
|
||||||
{
|
{
|
||||||
mInterval = interval;
|
mInterval = interval;
|
||||||
|
|
||||||
mRunning.set(false);
|
mRunning.set(false);
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum Interval
|
public enum Interval
|
||||||
{
|
{
|
||||||
ONCE("Once"),
|
ONCE("Once"),
|
||||||
DELAYED_RESET("Once, Reset After Delay"),
|
DELAYED_RESET("Once - Reset After Delay"),
|
||||||
UNTIL_DISMISSED("Until Dismissed");
|
UNTIL_DISMISSED("Until Dismissed");
|
||||||
|
|
||||||
private String mLabel;
|
private String mLabel;
|
||||||
|
|||||||
@@ -24,10 +24,43 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
|||||||
import io.github.dsheirer.alias.Alias;
|
import io.github.dsheirer.alias.Alias;
|
||||||
import io.github.dsheirer.alias.action.AliasActionType;
|
import io.github.dsheirer.alias.action.AliasActionType;
|
||||||
import io.github.dsheirer.alias.action.RecurringAction;
|
import io.github.dsheirer.alias.action.RecurringAction;
|
||||||
|
import io.github.dsheirer.audio.AudioFormats;
|
||||||
|
import io.github.dsheirer.gui.preference.playback.ToneFrequency;
|
||||||
|
import io.github.dsheirer.gui.preference.playback.ToneUtil;
|
||||||
|
import io.github.dsheirer.gui.preference.playback.ToneVolume;
|
||||||
import io.github.dsheirer.message.IMessage;
|
import io.github.dsheirer.message.IMessage;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.sound.sampled.AudioSystem;
|
||||||
|
import javax.sound.sampled.Clip;
|
||||||
|
import javax.sound.sampled.DataLine;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
public class BeepAction extends RecurringAction
|
public class BeepAction extends RecurringAction
|
||||||
{
|
{
|
||||||
|
private static final Logger mLog = LoggerFactory.getLogger(BeepAction.class);
|
||||||
|
private byte[] mToneBytes;
|
||||||
|
|
||||||
|
public BeepAction()
|
||||||
|
{
|
||||||
|
setInterval(Interval.ONCE);
|
||||||
|
float[] tone = ToneUtil.getTone(ToneFrequency.F700, ToneVolume.V10, 1000);
|
||||||
|
|
||||||
|
/* Little-endian byte buffer */
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(tone.length * 2).order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
|
ShortBuffer shortBuffer = buffer.asShortBuffer();
|
||||||
|
|
||||||
|
for(float sample : tone)
|
||||||
|
{
|
||||||
|
shortBuffer.put((short) (sample * Short.MAX_VALUE));
|
||||||
|
}
|
||||||
|
|
||||||
|
mToneBytes = buffer.array();
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||||
@Override
|
@Override
|
||||||
@@ -39,12 +72,48 @@ public class BeepAction extends RecurringAction
|
|||||||
@Override
|
@Override
|
||||||
public void performAction(Alias alias, IMessage message )
|
public void performAction(Alias alias, IMessage message )
|
||||||
{
|
{
|
||||||
System.out.println( "\007" );
|
DataLine.Info info = new DataLine.Info(Clip.class, AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO);
|
||||||
|
|
||||||
|
if(!AudioSystem.isLineSupported(info))
|
||||||
|
{
|
||||||
|
mLog.error("Audio clip playback is not supported on this system");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Clip clip = (Clip)AudioSystem.getLine(info);
|
||||||
|
clip.open(AudioFormats.PCM_SIGNED_8KHZ_16BITS_MONO, mToneBytes, 0, mToneBytes.length);
|
||||||
|
clip.start();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
mLog.error("Error attempting to play audio test tone");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return "Beep";
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Beep");
|
||||||
|
|
||||||
|
if(getInterval() != null)
|
||||||
|
{
|
||||||
|
switch(getInterval())
|
||||||
|
{
|
||||||
|
case ONCE:
|
||||||
|
sb.append(" Once");
|
||||||
|
break;
|
||||||
|
case DELAYED_RESET:
|
||||||
|
sb.append(" Once, Reset After ").append(getPeriod()).append(" Seconds");
|
||||||
|
break;
|
||||||
|
case UNTIL_DISMISSED:
|
||||||
|
sb.append(" Every ").append(getPeriod()).append(" Seconds Until Dismissed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,185 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.action.beep;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.action.AliasAction;
|
|
||||||
import io.github.dsheirer.alias.action.RecurringAction;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class BeepActionEditor extends DocumentListenerEditor<AliasAction>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT =
|
|
||||||
"<html><h3>Beep Action</h3>"
|
|
||||||
+ "This action will sound a beep according to the interval<br>"
|
|
||||||
+ "that you select:<br><br>"
|
|
||||||
+ "<b>Once:</b> Beep the first time the alias is active and<br>"
|
|
||||||
+ "never again<br><br>"
|
|
||||||
+ "<b>Once, Reset After Delay:</b> Beep once and suppress<br>"
|
|
||||||
+ "subsequent beeps for the specified period in seconds.<br>"
|
|
||||||
+ "After the reset period, beep again when the alias is active.<br><br>"
|
|
||||||
+ "<b>Until Dismissed:</b> Beep every period seconds until you<br>"
|
|
||||||
+ "click OK on the dialog that appears. Alerting is suppressed<br>"
|
|
||||||
+ "for 15 seconds after you click OK.<br>"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JComboBox<RecurringAction.Interval> mComboInterval;
|
|
||||||
private JSlider mPeriodSlider;
|
|
||||||
private JLabel mPeriodSliderLabel;
|
|
||||||
|
|
||||||
public BeepActionEditor( AliasAction aliasAction )
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
setItem( aliasAction );
|
|
||||||
}
|
|
||||||
|
|
||||||
public BeepAction getBeepAction()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof BeepAction )
|
|
||||||
{
|
|
||||||
return (BeepAction)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Beep Interval:" ) );
|
|
||||||
|
|
||||||
mComboInterval = new JComboBox<RecurringAction.Interval>( RecurringAction.Interval.values() );
|
|
||||||
mComboInterval.setToolTipText( HELP_TEXT );
|
|
||||||
mComboInterval.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
RecurringAction.Interval selected = mComboInterval
|
|
||||||
.getItemAt( mComboInterval.getSelectedIndex() );
|
|
||||||
|
|
||||||
if( selected != null )
|
|
||||||
{
|
|
||||||
/* Enable/disable period spinner based on selection */
|
|
||||||
boolean enabled = selected != RecurringAction.Interval.ONCE;
|
|
||||||
|
|
||||||
mPeriodSlider.setEnabled( enabled );
|
|
||||||
mPeriodSliderLabel.setEnabled( enabled );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add( mComboInterval, "wrap" );
|
|
||||||
|
|
||||||
final SpinnerModel model = new SpinnerNumberModel( 1, 1, 30, 1 );
|
|
||||||
model.addChangeListener( new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged( ChangeEvent e )
|
|
||||||
{
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
mPeriodSlider = new JSlider( JSlider.HORIZONTAL, 1, 60, 1 );
|
|
||||||
mPeriodSlider.setMajorTickSpacing( 10 );
|
|
||||||
mPeriodSlider.setMinorTickSpacing( 2 );
|
|
||||||
mPeriodSlider.setPaintTicks( true );
|
|
||||||
mPeriodSlider.setLabelTable( mPeriodSlider.createStandardLabels( 10, 10 ) );
|
|
||||||
mPeriodSlider.setPaintLabels( true );
|
|
||||||
mPeriodSlider.addChangeListener( new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged( ChangeEvent e )
|
|
||||||
{
|
|
||||||
mPeriodSliderLabel.setText( "Period: " + mPeriodSlider.getValue() );
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
mPeriodSlider.setToolTipText( HELP_TEXT );
|
|
||||||
|
|
||||||
mPeriodSliderLabel = new JLabel( "Period: " + mPeriodSlider.getValue() + " " );
|
|
||||||
add( mPeriodSliderLabel );
|
|
||||||
add( mPeriodSlider, "wrap,grow" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( BeepActionEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasAction item )
|
|
||||||
{
|
|
||||||
super.setItem( item );
|
|
||||||
|
|
||||||
if( hasItem() )
|
|
||||||
{
|
|
||||||
BeepAction beep = getBeepAction();
|
|
||||||
|
|
||||||
RecurringAction.Interval interval = beep.getInterval();
|
|
||||||
|
|
||||||
mComboInterval.setSelectedItem( interval );
|
|
||||||
|
|
||||||
boolean enabled = interval != RecurringAction.Interval.ONCE;
|
|
||||||
|
|
||||||
mPeriodSliderLabel.setEnabled( enabled );
|
|
||||||
mPeriodSlider.setEnabled( enabled );
|
|
||||||
mPeriodSlider.setValue( beep.getPeriod() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if( hasItem() && isModified() )
|
|
||||||
{
|
|
||||||
BeepAction beep = getBeepAction();
|
|
||||||
|
|
||||||
beep.setInterval( (RecurringAction.Interval)mComboInterval.getSelectedItem() );
|
|
||||||
beep.setPeriod( mPeriodSlider.getValue() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -45,6 +45,7 @@ public class ClipAction extends RecurringAction
|
|||||||
|
|
||||||
public ClipAction()
|
public ClipAction()
|
||||||
{
|
{
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||||
@@ -62,6 +63,7 @@ public class ClipAction extends RecurringAction
|
|||||||
public void setPath(String path)
|
public void setPath(String path)
|
||||||
{
|
{
|
||||||
mFilePath = path;
|
mFilePath = path;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -87,8 +89,7 @@ public class ClipAction extends RecurringAction
|
|||||||
{
|
{
|
||||||
mClip = AudioSystem.getClip();
|
mClip = AudioSystem.getClip();
|
||||||
|
|
||||||
AudioInputStream ais =
|
AudioInputStream ais = AudioSystem.getAudioInputStream(new File(mFilePath));
|
||||||
AudioSystem.getAudioInputStream(new File(mFilePath));
|
|
||||||
|
|
||||||
mClip.open(ais);
|
mClip.open(ais);
|
||||||
}
|
}
|
||||||
@@ -113,17 +114,33 @@ public class ClipAction extends RecurringAction
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
if(mFilePath == null)
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Play Audio Clip");
|
||||||
|
|
||||||
|
if(getInterval() != null)
|
||||||
{
|
{
|
||||||
return "Play Clip";
|
switch(getInterval())
|
||||||
|
{
|
||||||
|
case ONCE:
|
||||||
|
sb.append(" Once");
|
||||||
|
break;
|
||||||
|
case DELAYED_RESET:
|
||||||
|
sb.append(" Once, Reset After ").append(getPeriod()).append(" Seconds");
|
||||||
|
break;
|
||||||
|
case UNTIL_DISMISSED:
|
||||||
|
sb.append(" Every ").append(getPeriod()).append(" Seconds Until Dismissed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if(getPath() == null)
|
||||||
{
|
{
|
||||||
return "Play Clip: " + mFilePath;
|
sb.append(" - (audio file empty)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,285 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.action.clip;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.action.AliasAction;
|
|
||||||
import io.github.dsheirer.alias.action.RecurringAction;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class ClipActionEditor extends DocumentListenerEditor<AliasAction>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String PLEASE_SELECT_A_FILE = "Please select a file";
|
|
||||||
private static final String HELP_TEXT =
|
|
||||||
"<html><h3>Clip Action</h3>"
|
|
||||||
+ "This action will play an audio clip according to the interval<br>"
|
|
||||||
+ "that you select:<br><br>"
|
|
||||||
+ "<b>Once:</b> play the first time the alias is active and<br>"
|
|
||||||
+ "never again<br><br>"
|
|
||||||
+ "<b>Once, Reset After Delay:</b> play once and suppress<br>"
|
|
||||||
+ "subsequent runs for the specified period in seconds.<br>"
|
|
||||||
+ "After the reset period, play again when the alias is active.<br><br>"
|
|
||||||
+ "<b>Until Dismissed:</b> play every period seconds until you<br>"
|
|
||||||
+ "click OK on the dialog that appears. Alerting is suppressed<br>"
|
|
||||||
+ "for 15 seconds after you click OK.<br>"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JComboBox<RecurringAction.Interval> mComboInterval;
|
|
||||||
private JSlider mPeriodSlider;
|
|
||||||
private JLabel mPeriodSliderLabel;
|
|
||||||
private JTextField mTextFilePath;
|
|
||||||
|
|
||||||
public ClipActionEditor( AliasAction aliasAction )
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
setItem( aliasAction );
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClipAction getClipAction()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof ClipAction )
|
|
||||||
{
|
|
||||||
return (ClipAction)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Play Interval:" ) );
|
|
||||||
|
|
||||||
mComboInterval = new JComboBox<RecurringAction.Interval>( RecurringAction.Interval.values() );
|
|
||||||
mComboInterval.setToolTipText( HELP_TEXT );
|
|
||||||
mComboInterval.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
RecurringAction.Interval selected = mComboInterval
|
|
||||||
.getItemAt( mComboInterval.getSelectedIndex() );
|
|
||||||
|
|
||||||
if( selected != null )
|
|
||||||
{
|
|
||||||
/* Enable/disable period slider based on selection */
|
|
||||||
boolean enabled = selected != RecurringAction.Interval.ONCE;
|
|
||||||
|
|
||||||
mPeriodSlider.setEnabled( enabled );
|
|
||||||
mPeriodSliderLabel.setEnabled( enabled );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add( mComboInterval );
|
|
||||||
|
|
||||||
final SpinnerModel model = new SpinnerNumberModel( 1, 1, 30, 1 );
|
|
||||||
model.addChangeListener( new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged( ChangeEvent e )
|
|
||||||
{
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
mPeriodSlider = new JSlider( JSlider.HORIZONTAL, 1, 60, 1 );
|
|
||||||
mPeriodSlider.setMajorTickSpacing( 10 );
|
|
||||||
mPeriodSlider.setMinorTickSpacing( 2 );
|
|
||||||
mPeriodSlider.setPaintTicks( true );
|
|
||||||
mPeriodSlider.setLabelTable( mPeriodSlider.createStandardLabels( 10, 10 ) );
|
|
||||||
mPeriodSlider.setPaintLabels( true );
|
|
||||||
mPeriodSlider.addChangeListener( new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged( ChangeEvent e )
|
|
||||||
{
|
|
||||||
mPeriodSliderLabel.setText( "Period: " + mPeriodSlider.getValue() );
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
mPeriodSlider.setToolTipText( HELP_TEXT );
|
|
||||||
|
|
||||||
mPeriodSliderLabel = new JLabel( "Period: " + mPeriodSlider.getValue() + " " );
|
|
||||||
add( mPeriodSliderLabel );
|
|
||||||
add( mPeriodSlider, "wrap,grow" );
|
|
||||||
|
|
||||||
mTextFilePath = new JTextField( PLEASE_SELECT_A_FILE );
|
|
||||||
add( mTextFilePath, "growx,span" );
|
|
||||||
|
|
||||||
JButton fileButton = new JButton( "File" );
|
|
||||||
|
|
||||||
fileButton.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
final JFileChooser chooser = new JFileChooser();
|
|
||||||
|
|
||||||
int value = chooser.showOpenDialog( ClipActionEditor.this );
|
|
||||||
|
|
||||||
if( value == JFileChooser.APPROVE_OPTION )
|
|
||||||
{
|
|
||||||
File file = chooser.getSelectedFile();
|
|
||||||
|
|
||||||
mTextFilePath.setText( file.getAbsolutePath() );
|
|
||||||
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( fileButton, "grow" );
|
|
||||||
|
|
||||||
JButton testButton = new JButton( "Test" );
|
|
||||||
|
|
||||||
testButton.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
if( hasItem() )
|
|
||||||
{
|
|
||||||
String path = mTextFilePath.getText();
|
|
||||||
|
|
||||||
if( path == null || path.trim().isEmpty() )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( ClipActionEditor.this,
|
|
||||||
"Please select an audio file", PLEASE_SELECT_A_FILE,
|
|
||||||
JOptionPane.ERROR_MESSAGE );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( isModified() )
|
|
||||||
{
|
|
||||||
int option = JOptionPane.showConfirmDialog(
|
|
||||||
ClipActionEditor.this,
|
|
||||||
"Settings have changed. Do you want to save these changes?",
|
|
||||||
"Save Changes?",
|
|
||||||
JOptionPane.YES_NO_OPTION,
|
|
||||||
JOptionPane.QUESTION_MESSAGE );
|
|
||||||
|
|
||||||
if( option == JOptionPane.YES_OPTION )
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new Thread( new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
getClipAction().play();
|
|
||||||
}
|
|
||||||
catch( Exception e1 )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( ClipActionEditor.this,
|
|
||||||
"Couldn't play audio clip [" + e1.getMessage() + "]",
|
|
||||||
"Error", JOptionPane.ERROR_MESSAGE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( testButton, "grow,wrap" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( ClipActionEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasAction item )
|
|
||||||
{
|
|
||||||
super.setItem( item );
|
|
||||||
|
|
||||||
if( hasItem() )
|
|
||||||
{
|
|
||||||
ClipAction clip = getClipAction();
|
|
||||||
|
|
||||||
RecurringAction.Interval interval = clip.getInterval();
|
|
||||||
|
|
||||||
mComboInterval.setSelectedItem( interval );
|
|
||||||
|
|
||||||
boolean enabled = interval != RecurringAction.Interval.ONCE;
|
|
||||||
|
|
||||||
mPeriodSliderLabel.setEnabled( enabled );
|
|
||||||
mPeriodSlider.setEnabled( enabled );
|
|
||||||
mPeriodSlider.setValue( clip.getPeriod() );
|
|
||||||
|
|
||||||
String filepath = clip.getPath();
|
|
||||||
|
|
||||||
if( filepath != null && !filepath.isEmpty() )
|
|
||||||
{
|
|
||||||
mTextFilePath.setText( filepath );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mTextFilePath.setText( PLEASE_SELECT_A_FILE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if( hasItem() && isModified() )
|
|
||||||
{
|
|
||||||
ClipAction script = getClipAction();
|
|
||||||
|
|
||||||
script.setInterval( (RecurringAction.Interval)mComboInterval.getSelectedItem() );
|
|
||||||
script.setPeriod( mPeriodSlider.getValue() );
|
|
||||||
script.setPath( mTextFilePath.getText() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -39,6 +39,7 @@ public class ScriptAction extends RecurringAction
|
|||||||
|
|
||||||
public ScriptAction()
|
public ScriptAction()
|
||||||
{
|
{
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||||
@@ -56,6 +57,7 @@ public class ScriptAction extends RecurringAction
|
|||||||
public void setScript(String script)
|
public void setScript(String script)
|
||||||
{
|
{
|
||||||
mScript = script;
|
mScript = script;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -104,13 +106,30 @@ public class ScriptAction extends RecurringAction
|
|||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
if(mScript == null)
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Run Script");
|
||||||
|
|
||||||
|
if(getInterval() != null)
|
||||||
{
|
{
|
||||||
return "Run Script";
|
switch(getInterval())
|
||||||
|
{
|
||||||
|
case ONCE:
|
||||||
|
sb.append(" Once");
|
||||||
|
break;
|
||||||
|
case DELAYED_RESET:
|
||||||
|
sb.append(" Once, Reset After ").append(getPeriod()).append(" Seconds");
|
||||||
|
break;
|
||||||
|
case UNTIL_DISMISSED:
|
||||||
|
sb.append(" Every ").append(getPeriod()).append(" Seconds Until Dismissed");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if(getScript() == null)
|
||||||
{
|
{
|
||||||
return "Run Script: " + mScript;
|
sb.append(" - (script file empty)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,281 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.action.script;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.action.AliasAction;
|
|
||||||
import io.github.dsheirer.alias.action.RecurringAction;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class ScriptActionEditor extends DocumentListenerEditor<AliasAction>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String PLEASE_SELECT_A_FILE = "Please select a file";
|
|
||||||
private static final String HELP_TEXT =
|
|
||||||
"<html><h3>Script Action</h3>"
|
|
||||||
+ "This action will run a script according to the interval<br>"
|
|
||||||
+ "that you select:<br><br>"
|
|
||||||
+ "<b>Once:</b> run the first time the alias is active and<br>"
|
|
||||||
+ "never again<br><br>"
|
|
||||||
+ "<b>Once, Reset After Delay:</b> run once and suppress<br>"
|
|
||||||
+ "subsequent runs for the specified period in seconds.<br>"
|
|
||||||
+ "After the reset period, run again when the alias is active.<br><br>"
|
|
||||||
+ "<b>Until Dismissed:</b> run every period seconds until you<br>"
|
|
||||||
+ "click OK on the dialog that appears. Alerting is suppressed<br>"
|
|
||||||
+ "for 15 seconds after you click OK.<br>"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JComboBox<RecurringAction.Interval> mComboInterval;
|
|
||||||
private JSlider mPeriodSlider;
|
|
||||||
private JLabel mPeriodSliderLabel;
|
|
||||||
private JTextField mTextFilePath;
|
|
||||||
|
|
||||||
public ScriptActionEditor( AliasAction aliasAction )
|
|
||||||
{
|
|
||||||
init();
|
|
||||||
|
|
||||||
setItem( aliasAction );
|
|
||||||
}
|
|
||||||
|
|
||||||
public ScriptAction getScriptAction()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof ScriptAction )
|
|
||||||
{
|
|
||||||
return (ScriptAction)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][][][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Run Interval:" ) );
|
|
||||||
|
|
||||||
mComboInterval = new JComboBox<RecurringAction.Interval>( RecurringAction.Interval.values() );
|
|
||||||
mComboInterval.setToolTipText( HELP_TEXT );
|
|
||||||
mComboInterval.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
RecurringAction.Interval selected = mComboInterval
|
|
||||||
.getItemAt( mComboInterval.getSelectedIndex() );
|
|
||||||
|
|
||||||
if( selected != null )
|
|
||||||
{
|
|
||||||
/* Enable/disable period slider based on selection */
|
|
||||||
boolean enabled = selected != RecurringAction.Interval.ONCE;
|
|
||||||
|
|
||||||
mPeriodSlider.setEnabled( enabled );
|
|
||||||
mPeriodSliderLabel.setEnabled( enabled );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add( mComboInterval );
|
|
||||||
|
|
||||||
final SpinnerModel model = new SpinnerNumberModel( 1, 1, 30, 1 );
|
|
||||||
model.addChangeListener( new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged( ChangeEvent e )
|
|
||||||
{
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
mPeriodSlider = new JSlider( JSlider.HORIZONTAL, 1, 60, 1 );
|
|
||||||
mPeriodSlider.setMajorTickSpacing( 10 );
|
|
||||||
mPeriodSlider.setMinorTickSpacing( 2 );
|
|
||||||
mPeriodSlider.setPaintTicks( true );
|
|
||||||
mPeriodSlider.setLabelTable( mPeriodSlider.createStandardLabels( 10, 10 ) );
|
|
||||||
mPeriodSlider.setPaintLabels( true );
|
|
||||||
mPeriodSlider.addChangeListener( new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged( ChangeEvent e )
|
|
||||||
{
|
|
||||||
mPeriodSliderLabel.setText( "Period: " + mPeriodSlider.getValue() );
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
mPeriodSlider.setToolTipText( HELP_TEXT );
|
|
||||||
|
|
||||||
mPeriodSliderLabel = new JLabel( "Period: " + mPeriodSlider.getValue() + " " );
|
|
||||||
add( mPeriodSliderLabel );
|
|
||||||
add( mPeriodSlider, "wrap,grow" );
|
|
||||||
|
|
||||||
mTextFilePath = new JTextField( PLEASE_SELECT_A_FILE );
|
|
||||||
add( mTextFilePath, "growx,span" );
|
|
||||||
|
|
||||||
JButton fileButton = new JButton( "File" );
|
|
||||||
|
|
||||||
fileButton.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
final JFileChooser chooser = new JFileChooser();
|
|
||||||
|
|
||||||
int value = chooser.showOpenDialog( ScriptActionEditor.this );
|
|
||||||
|
|
||||||
if( value == JFileChooser.APPROVE_OPTION )
|
|
||||||
{
|
|
||||||
File file = chooser.getSelectedFile();
|
|
||||||
|
|
||||||
mTextFilePath.setText( file.getAbsolutePath() );
|
|
||||||
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( fileButton, "grow" );
|
|
||||||
|
|
||||||
JButton testButton = new JButton( "Test" );
|
|
||||||
testButton.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent actionEvent )
|
|
||||||
{
|
|
||||||
String script = mTextFilePath.getText();
|
|
||||||
|
|
||||||
if( script == null || script.trim().isEmpty() )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( ScriptActionEditor.this,
|
|
||||||
"Please select a script file", PLEASE_SELECT_A_FILE,
|
|
||||||
JOptionPane.ERROR_MESSAGE );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( isModified() )
|
|
||||||
{
|
|
||||||
int option = JOptionPane.showConfirmDialog(
|
|
||||||
ScriptActionEditor.this,
|
|
||||||
"Settings have changed. Do you want to save these changes?",
|
|
||||||
"Save Changes?",
|
|
||||||
JOptionPane.YES_NO_OPTION,
|
|
||||||
JOptionPane.QUESTION_MESSAGE );
|
|
||||||
|
|
||||||
if( option == JOptionPane.YES_OPTION )
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new Thread( new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
getScriptAction().play();
|
|
||||||
}
|
|
||||||
catch( Exception e1 )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( ScriptActionEditor.this,
|
|
||||||
e1.getMessage(), "Error", JOptionPane.ERROR_MESSAGE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).start();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( testButton, "grow,wrap" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( ScriptActionEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasAction item )
|
|
||||||
{
|
|
||||||
super.setItem( item );
|
|
||||||
|
|
||||||
if( hasItem() )
|
|
||||||
{
|
|
||||||
ScriptAction script = getScriptAction();
|
|
||||||
|
|
||||||
RecurringAction.Interval interval = script.getInterval();
|
|
||||||
|
|
||||||
mComboInterval.setSelectedItem( interval );
|
|
||||||
|
|
||||||
boolean enabled = interval != RecurringAction.Interval.ONCE;
|
|
||||||
|
|
||||||
mPeriodSliderLabel.setEnabled( enabled );
|
|
||||||
mPeriodSlider.setEnabled( enabled );
|
|
||||||
mPeriodSlider.setValue( script.getPeriod() );
|
|
||||||
|
|
||||||
String filepath = script.getScript();
|
|
||||||
|
|
||||||
if( filepath != null && !filepath.isEmpty() )
|
|
||||||
{
|
|
||||||
mTextFilePath.setText( filepath );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mTextFilePath.setText( PLEASE_SELECT_A_FILE );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if( hasItem() && isModified() )
|
|
||||||
{
|
|
||||||
ScriptAction script = getScriptAction();
|
|
||||||
|
|
||||||
script.setInterval( (RecurringAction.Interval)mComboInterval.getSelectedItem() );
|
|
||||||
script.setPeriod( mPeriodSlider.getValue() );
|
|
||||||
script.setScript( mTextFilePath.getText() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -40,43 +40,126 @@ import io.github.dsheirer.alias.id.priority.Priority;
|
|||||||
import io.github.dsheirer.alias.id.radio.Radio;
|
import io.github.dsheirer.alias.id.radio.Radio;
|
||||||
import io.github.dsheirer.alias.id.radio.RadioRange;
|
import io.github.dsheirer.alias.id.radio.RadioRange;
|
||||||
import io.github.dsheirer.alias.id.record.Record;
|
import io.github.dsheirer.alias.id.record.Record;
|
||||||
import io.github.dsheirer.alias.id.status.StatusID;
|
import io.github.dsheirer.alias.id.status.UnitStatusID;
|
||||||
|
import io.github.dsheirer.alias.id.status.UserStatusID;
|
||||||
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
|
import io.github.dsheirer.alias.id.talkgroup.Talkgroup;
|
||||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
|
import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
|
||||||
|
import io.github.dsheirer.alias.id.tone.TonesID;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
|
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
|
||||||
@JsonSubTypes({
|
@JsonSubTypes({
|
||||||
@JsonSubTypes.Type(value = BroadcastChannel.class, name = "broadcastChannel"),
|
@JsonSubTypes.Type(value = BroadcastChannel.class, name = "broadcastChannel"),
|
||||||
@JsonSubTypes.Type(value = Esn.class, name = "esn"),
|
@JsonSubTypes.Type(value = Esn.class, name = "esn"),
|
||||||
@JsonSubTypes.Type(value = FleetsyncID.class, name = "fleetsyncID"),
|
@JsonSubTypes.Type(value = FleetsyncID.class, name = "fleetsyncID"),
|
||||||
|
@JsonSubTypes.Type(value = LegacyTalkgroupID.class, name = "talkgroupID"),
|
||||||
@JsonSubTypes.Type(value = LoJackFunctionAndID.class, name = "loJackFunctionAndID"),
|
@JsonSubTypes.Type(value = LoJackFunctionAndID.class, name = "loJackFunctionAndID"),
|
||||||
@JsonSubTypes.Type(value = MDC1200ID.class, name = "mdc1200ID"),
|
@JsonSubTypes.Type(value = MDC1200ID.class, name = "mdc1200ID"),
|
||||||
@JsonSubTypes.Type(value = Min.class, name = "min"),
|
@JsonSubTypes.Type(value = Min.class, name = "min"),
|
||||||
@JsonSubTypes.Type(value = MPT1327ID.class, name = "mpt1327ID"),
|
@JsonSubTypes.Type(value = MPT1327ID.class, name = "mpt1327ID"),
|
||||||
@JsonSubTypes.Type(value = NonRecordable.class, name = "nonRecordable"),
|
@JsonSubTypes.Type(value = NonRecordable.class, name = "nonRecordable"),
|
||||||
|
@JsonSubTypes.Type(value = Priority.class, name = "priority"),
|
||||||
@JsonSubTypes.Type(value = Radio.class, name = "radio"),
|
@JsonSubTypes.Type(value = Radio.class, name = "radio"),
|
||||||
@JsonSubTypes.Type(value = RadioRange.class, name = "radioRange"),
|
@JsonSubTypes.Type(value = RadioRange.class, name = "radioRange"),
|
||||||
@JsonSubTypes.Type(value = Talkgroup.class, name = "talkgroup"),
|
|
||||||
@JsonSubTypes.Type(value = TalkgroupRange.class, name = "talkgroupRange"),
|
|
||||||
@JsonSubTypes.Type(value = Priority.class, name = "priority"),
|
|
||||||
@JsonSubTypes.Type(value = Record.class, name = "record"),
|
@JsonSubTypes.Type(value = Record.class, name = "record"),
|
||||||
@JsonSubTypes.Type(value = SiteID.class, name = "siteID"),
|
@JsonSubTypes.Type(value = SiteID.class, name = "siteID"),
|
||||||
@JsonSubTypes.Type(value = StatusID.class, name = "statusID"),
|
@JsonSubTypes.Type(value = Talkgroup.class, name = "talkgroup"),
|
||||||
@JsonSubTypes.Type(value = LegacyTalkgroupID.class, name = "talkgroupID"),
|
@JsonSubTypes.Type(value = TalkgroupRange.class, name = "talkgroupRange"),
|
||||||
|
@JsonSubTypes.Type(value = TonesID.class, name = "tones"),
|
||||||
|
@JsonSubTypes.Type(value = UserStatusID.class, name = "statusID"),
|
||||||
|
@JsonSubTypes.Type(value = UnitStatusID.class, name = "unitStatusID"),
|
||||||
@JsonSubTypes.Type(value = UniqueID.class, name = "uniqueID")
|
@JsonSubTypes.Type(value = UniqueID.class, name = "uniqueID")
|
||||||
})
|
})
|
||||||
@JacksonXmlRootElement(localName = "id")
|
@JacksonXmlRootElement(localName = "id")
|
||||||
public abstract class AliasID
|
public abstract class AliasID
|
||||||
{
|
{
|
||||||
|
private SimpleStringProperty mValueProperty = new SimpleStringProperty();
|
||||||
|
private BooleanProperty mOverlapProperty = new SimpleBooleanProperty();
|
||||||
|
|
||||||
public AliasID()
|
public AliasID()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String property representation of this alias ID
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public SimpleStringProperty valueProperty()
|
||||||
|
{
|
||||||
|
return mValueProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this alias identifier overlaps with any other alias identifier in the same alias list
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public BooleanProperty overlapProperty()
|
||||||
|
{
|
||||||
|
return mOverlapProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the overlap flag for this alias id. Overlap indicates that this identifier collides with another
|
||||||
|
* identifier within the same alias list.
|
||||||
|
*/
|
||||||
|
public void setOverlap(boolean overlap)
|
||||||
|
{
|
||||||
|
mOverlapProperty.set(overlap);
|
||||||
|
updateValueProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the value property for this alias ID. Note: this method is intended to be invoked by all subclasses
|
||||||
|
* each time that any of the subclass member variable values change.
|
||||||
|
*/
|
||||||
|
public void updateValueProperty()
|
||||||
|
{
|
||||||
|
if(overlapProperty().get())
|
||||||
|
{
|
||||||
|
valueProperty().set(toString() + " - Error: Overlap");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
valueProperty().set(toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Hack: harmless, but the list extractor does not consistently update unless we do this.
|
||||||
|
valueProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public abstract AliasIDType getType();
|
public abstract AliasIDType getType();
|
||||||
|
|
||||||
public abstract boolean matches(AliasID id);
|
public abstract boolean matches(AliasID id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if this alias ID overlaps with another alias ID.
|
||||||
|
* Note: this method is intended to be overridden by certain subclass implementations.
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public boolean overlaps(AliasID id)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public abstract boolean isValid();
|
public abstract boolean isValid();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the identifier is an audio identifier (monitor, record, stream)
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public abstract boolean isAudioIdentifier();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
|
||||||
|
*/
|
||||||
|
public static Callback<AliasID,Observable[]> extractor()
|
||||||
|
{
|
||||||
|
return (AliasID aid) -> new Observable[] {aid.valueProperty(), aid.overlapProperty()};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@
|
|||||||
*/
|
*/
|
||||||
package io.github.dsheirer.alias.id;
|
package io.github.dsheirer.alias.id;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
public enum AliasIDType
|
public enum AliasIDType
|
||||||
{
|
{
|
||||||
BROADCAST_CHANNEL("Audio Broadcast Channel"),
|
BROADCAST_CHANNEL("Audio Broadcast Channel"),
|
||||||
@@ -34,7 +36,9 @@ public enum AliasIDType
|
|||||||
RADIO_ID_RANGE("Radio ID Range"),
|
RADIO_ID_RANGE("Radio ID Range"),
|
||||||
RECORD("Record"),
|
RECORD("Record"),
|
||||||
SITE("Site"),
|
SITE("Site"),
|
||||||
STATUS("Status"),
|
STATUS("User Status"),
|
||||||
|
TONES("Tone Sequence"),
|
||||||
|
UNIT_STATUS("Unit Status"),
|
||||||
TALKGROUP("Talkgroup"),
|
TALKGROUP("Talkgroup"),
|
||||||
TALKGROUP_RANGE("Talkgroup Range"),
|
TALKGROUP_RANGE("Talkgroup Range"),
|
||||||
|
|
||||||
@@ -52,6 +56,10 @@ public enum AliasIDType
|
|||||||
mLabel = label;
|
mLabel = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Values used by the View-By alias editor
|
||||||
|
public static EnumSet<AliasIDType> VIEW_BY_VALUES = EnumSet.of(TALKGROUP, TALKGROUP_RANGE, RADIO_ID, RADIO_ID_RANGE,
|
||||||
|
UNIT_STATUS, STATUS, TONES);
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return mLabel;
|
return mLabel;
|
||||||
|
|||||||
@@ -1,370 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * ******************************************************************************
|
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
* *
|
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
|
||||||
* * it under the terms of the GNU General Public License as published by
|
|
||||||
* * the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* * (at your option) any later version.
|
|
||||||
* *
|
|
||||||
* * This program is distributed in the hope that it will be useful,
|
|
||||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* * GNU General Public License for more details.
|
|
||||||
* *
|
|
||||||
* * You should have received a copy of the GNU General Public License
|
|
||||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* * *****************************************************************************
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.Alias;
|
|
||||||
import io.github.dsheirer.alias.AliasEvent;
|
|
||||||
import io.github.dsheirer.alias.AliasFactory;
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.gui.editor.EmptyEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.DefaultListModel;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JPopupMenu;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.ListModel;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AliasIdentifierEditor extends Editor<Alias>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static ListModel<AliasID> EMPTY_MODEL = new DefaultListModel<>();
|
|
||||||
private JList<AliasID> mAliasIDList = new JList<>(EMPTY_MODEL);
|
|
||||||
private JButton mNewIDButton;
|
|
||||||
private JButton mCloneIDButton;
|
|
||||||
private JButton mDeleteIDButton;
|
|
||||||
private EditorContainer mEditorContainer = new EditorContainer();
|
|
||||||
|
|
||||||
private AliasModel mAliasModel;
|
|
||||||
private BroadcastModel mBroadcastModel;
|
|
||||||
|
|
||||||
public AliasIdentifierEditor(AliasModel aliasModel, BroadcastModel broadcastModel)
|
|
||||||
{
|
|
||||||
mAliasModel = aliasModel;
|
|
||||||
mBroadcastModel = broadcastModel;
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 3",
|
|
||||||
"[grow,fill][grow,fill][grow,fill]", "[][grow,fill][]"));
|
|
||||||
|
|
||||||
mAliasIDList.setVisibleRowCount(6);
|
|
||||||
mAliasIDList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
mAliasIDList.setLayoutOrientation(JList.VERTICAL);
|
|
||||||
mAliasIDList.addListSelectionListener(new ListSelectionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void valueChanged(ListSelectionEvent event)
|
|
||||||
{
|
|
||||||
if(!event.getValueIsAdjusting())
|
|
||||||
{
|
|
||||||
JList<?> list = (JList<?>)event.getSource();
|
|
||||||
|
|
||||||
Object selectedItem = list.getSelectedValue();
|
|
||||||
|
|
||||||
if(selectedItem != null && selectedItem instanceof AliasID)
|
|
||||||
{
|
|
||||||
AliasID selected = (AliasID)selectedItem;
|
|
||||||
|
|
||||||
mEditorContainer.setAliasID(selected);
|
|
||||||
|
|
||||||
mCloneIDButton.setEnabled(true);
|
|
||||||
mDeleteIDButton.setEnabled(true);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mCloneIDButton.setEnabled(false);
|
|
||||||
mDeleteIDButton.setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JScrollPane scroller = new JScrollPane(mAliasIDList);
|
|
||||||
add(scroller, "span,grow");
|
|
||||||
|
|
||||||
add(mEditorContainer, "span,grow");
|
|
||||||
|
|
||||||
mNewIDButton = new JButton("New ...");
|
|
||||||
mNewIDButton.setToolTipText("Create a new Alias Identifier");
|
|
||||||
mNewIDButton.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
JPopupMenu menu = new JPopupMenu();
|
|
||||||
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.TALKGROUP));
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.TALKGROUP_RANGE));
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.RADIO_ID));
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.RADIO_ID_RANGE));
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.ESN));
|
|
||||||
// menu.add(new AddAliasIdentifierItem(AliasIDType.LOJACK));
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.STATUS));
|
|
||||||
|
|
||||||
menu.addSeparator();
|
|
||||||
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.BROADCAST_CHANNEL));
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
Alias alias = getItem();
|
|
||||||
|
|
||||||
if(!alias.isRecordable())
|
|
||||||
{
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.RECORD));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!alias.hasCallPriority())
|
|
||||||
{
|
|
||||||
menu.add(new AddAliasIdentifierItem(AliasIDType.PRIORITY));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mNewIDButton);
|
|
||||||
|
|
||||||
mCloneIDButton = new JButton("Clone");
|
|
||||||
mCloneIDButton.setToolTipText("Create a copy of the currently selected identifier");
|
|
||||||
mCloneIDButton.setEnabled(false);
|
|
||||||
mCloneIDButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
AliasID selected = mAliasIDList.getSelectedValue();
|
|
||||||
|
|
||||||
if(selected != null)
|
|
||||||
{
|
|
||||||
AliasID clone = AliasFactory.copyOf(selected);
|
|
||||||
|
|
||||||
if(clone != null)
|
|
||||||
{
|
|
||||||
addAliasIDToList(clone);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mCloneIDButton);
|
|
||||||
|
|
||||||
mDeleteIDButton = new JButton("Delete");
|
|
||||||
mDeleteIDButton.setToolTipText("Delete the currently selected identifier");
|
|
||||||
mDeleteIDButton.setEnabled(false);
|
|
||||||
mDeleteIDButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
final AliasID selected = mAliasIDList.getSelectedValue();
|
|
||||||
|
|
||||||
if(selected != null)
|
|
||||||
{
|
|
||||||
int choice = JOptionPane.showConfirmDialog(mDeleteIDButton,
|
|
||||||
"Do you want to delete [" + selected.toString() + "]",
|
|
||||||
"Are you sure?", JOptionPane.YES_NO_OPTION);
|
|
||||||
|
|
||||||
if(choice == JOptionPane.YES_OPTION && hasItem())
|
|
||||||
{
|
|
||||||
Alias alias = getItem();
|
|
||||||
|
|
||||||
alias.removeAliasID(selected);
|
|
||||||
|
|
||||||
mAliasModel.broadcast(new AliasEvent(alias, AliasEvent.Event.CHANGE));
|
|
||||||
|
|
||||||
setItem(alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mDeleteIDButton, "wrap");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(Alias alias)
|
|
||||||
{
|
|
||||||
super.setItem(alias);
|
|
||||||
|
|
||||||
if(alias == null || alias.getId().isEmpty())
|
|
||||||
{
|
|
||||||
mAliasIDList.setModel(EMPTY_MODEL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DefaultListModel<AliasID> model = new DefaultListModel<AliasID>();
|
|
||||||
|
|
||||||
List<AliasID> ids = alias.getId();
|
|
||||||
|
|
||||||
ids.sort(Comparator.comparing(Object::toString));
|
|
||||||
|
|
||||||
for(AliasID id : ids)
|
|
||||||
{
|
|
||||||
model.addElement(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
mAliasIDList.setModel(model);
|
|
||||||
}
|
|
||||||
|
|
||||||
mEditorContainer.setAliasID(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if(isModified() || mEditorContainer.isModified())
|
|
||||||
{
|
|
||||||
if(mEditorContainer.isModified())
|
|
||||||
{
|
|
||||||
mEditorContainer.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
mAliasModel.broadcast(new AliasEvent(getItem(), AliasEvent.Event.CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class EditorContainer extends JPanel
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private Editor<AliasID> mEditor = new EmptyEditor<>();
|
|
||||||
|
|
||||||
public EditorContainer()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("", "[grow,fill]", "[grow,fill]"));
|
|
||||||
|
|
||||||
add(mEditor);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isModified()
|
|
||||||
{
|
|
||||||
if(mEditor != null)
|
|
||||||
{
|
|
||||||
return mEditor.isModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if(mEditor != null)
|
|
||||||
{
|
|
||||||
mEditor.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAliasID(AliasID aliasID)
|
|
||||||
{
|
|
||||||
if(mEditor != null)
|
|
||||||
{
|
|
||||||
if(mEditor.isModified())
|
|
||||||
{
|
|
||||||
int option = JOptionPane.showConfirmDialog(
|
|
||||||
EditorContainer.this,
|
|
||||||
"Identifier settings have changed. Do you want to save these changes?",
|
|
||||||
"Save Changes?",
|
|
||||||
JOptionPane.YES_NO_OPTION,
|
|
||||||
JOptionPane.QUESTION_MESSAGE);
|
|
||||||
|
|
||||||
if(option == JOptionPane.YES_OPTION)
|
|
||||||
{
|
|
||||||
mEditor.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
removeAll();
|
|
||||||
|
|
||||||
//This will always give us an editor
|
|
||||||
mEditor = AliasFactory.getEditor(aliasID, mBroadcastModel);
|
|
||||||
|
|
||||||
add(mEditor);
|
|
||||||
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addAliasIDToList(final AliasID id)
|
|
||||||
{
|
|
||||||
if(id != null && hasItem())
|
|
||||||
{
|
|
||||||
final Alias alias = getItem();
|
|
||||||
|
|
||||||
alias.addAliasID(id);
|
|
||||||
|
|
||||||
EventQueue.invokeLater(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
setItem(alias);
|
|
||||||
|
|
||||||
mAliasIDList.setSelectedValue(id, true);
|
|
||||||
|
|
||||||
AliasIdentifierEditor.this.setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AddAliasIdentifierItem extends JMenuItem
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private AliasIDType mAliasIDType;
|
|
||||||
|
|
||||||
public AddAliasIdentifierItem(AliasIDType type)
|
|
||||||
{
|
|
||||||
super(type.toString());
|
|
||||||
|
|
||||||
mAliasIDType = type;
|
|
||||||
|
|
||||||
addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
final AliasID id = AliasFactory.getAliasID(mAliasIDType);
|
|
||||||
|
|
||||||
addAliasIDToList(id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,120 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* 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 <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id;
|
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.apache.commons.math3.util.FastMath;
|
|
||||||
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class WildcardID implements Comparable<WildcardID>
|
|
||||||
{
|
|
||||||
public static final String WILDCARD = "*";
|
|
||||||
public static final String REGEX_WILDCARD = ".";
|
|
||||||
|
|
||||||
private String mValue;
|
|
||||||
private Pattern mPattern;
|
|
||||||
private int mWeight;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wildcard identifier for matching to string identifiers containing single-character (*) wildcard values.
|
|
||||||
*
|
|
||||||
* Supports ordering from most-specific to least-specific using the build-in weighting calculation where identifier
|
|
||||||
* patterns containing fewer wildcards closer to the least significant digit will be weighted more heavily than
|
|
||||||
* identifier patterns containing more wildcards, or wildcard characters in the most significant digits.
|
|
||||||
*
|
|
||||||
* @param value is a string value containing one or more asterisk (*) single character wildcard with a maximum
|
|
||||||
* length of 10 characters.
|
|
||||||
*
|
|
||||||
* @throws AssertionError if the value is null, longer than 10 characters, or doesn't contain at least 1 asterisk
|
|
||||||
* @throws IllegalArgumentException if the value cannot be compiled as a regular expression after converting the
|
|
||||||
* asterisk characters to the regex single-character wildcard value (.)
|
|
||||||
*/
|
|
||||||
public WildcardID(String value)
|
|
||||||
{
|
|
||||||
Validate.isTrue(value != null && value.contains(WILDCARD) && value.length() < 10);
|
|
||||||
|
|
||||||
mValue = value;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mPattern = Pattern.compile(value.replace(WILDCARD, REGEX_WILDCARD));
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Invalid regex pattern for alias ID value [" + value + "]", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
mWeight = calculateWeight();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String value()
|
|
||||||
{
|
|
||||||
return mValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if the id matches the internal regex pattern for this wildcard alias ID
|
|
||||||
* @param id
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public boolean matches(String id)
|
|
||||||
{
|
|
||||||
return id != null && mPattern.matcher(id).matches();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int weight()
|
|
||||||
{
|
|
||||||
return mWeight;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates a weighting value for wildcard character quantity and significant digit location
|
|
||||||
*/
|
|
||||||
private int calculateWeight()
|
|
||||||
{
|
|
||||||
int weight = 0;
|
|
||||||
int characterCount = -1;
|
|
||||||
|
|
||||||
for( int x = 0; x < mValue.length(); x++)
|
|
||||||
{
|
|
||||||
if(mValue.substring(x, x + 1).equals(WILDCARD))
|
|
||||||
{
|
|
||||||
weight += (int)(FastMath.pow(2, mValue.length() - x - 1)); //Position weight
|
|
||||||
characterCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
weight += (int)(FastMath.pow(2, characterCount)) * 1000; //Character count weight
|
|
||||||
|
|
||||||
return weight;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compareTo(WildcardID otherWildcardID)
|
|
||||||
{
|
|
||||||
return Integer.compare(this.weight(), otherWildcardID.weight());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof WildcardID)) return false;
|
|
||||||
return compareTo((WildcardID) o) == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +1,24 @@
|
|||||||
/*******************************************************************************
|
/*
|
||||||
* sdrtrunk
|
|
||||||
* 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
*/
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.broadcast;
|
package io.github.dsheirer.alias.id.broadcast;
|
||||||
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
@@ -31,6 +34,12 @@ public class BroadcastChannel extends AliasID implements Comparable<BroadcastCha
|
|||||||
//JAXB Constructor
|
//JAXB Constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(BroadcastChannel other)
|
public int compareTo(BroadcastChannel other)
|
||||||
{
|
{
|
||||||
@@ -94,6 +103,7 @@ public class BroadcastChannel extends AliasID implements Comparable<BroadcastCha
|
|||||||
public void setChannelName(String channel)
|
public void setChannelName(String channel)
|
||||||
{
|
{
|
||||||
mChannelName = channel;
|
mChannelName = channel;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||||
@@ -118,13 +128,6 @@ public class BroadcastChannel extends AliasID implements Comparable<BroadcastCha
|
|||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
if(isValid())
|
return isValid() ? mChannelName : "(invalid)";
|
||||||
{
|
|
||||||
return "Broadcast Channel: " + mChannelName;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return "Broadcast Channel: None Selected";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,129 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* 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 <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.broadcast;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class BroadcastChannelEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Audio Broadcast Channel</h3>"
|
|
||||||
+ "Name of a audio streaming broadcast configuration<br>"
|
|
||||||
+ "to be used for streaming audio to an external<br>"
|
|
||||||
+ "streaming server";
|
|
||||||
|
|
||||||
private JComboBox<String> mBroadcastConfigurations;
|
|
||||||
private BroadcastModel mBroadcastModel;
|
|
||||||
|
|
||||||
public BroadcastChannelEditor(AliasID aliasID, BroadcastModel broadcastModel)
|
|
||||||
{
|
|
||||||
mBroadcastModel = broadcastModel;
|
|
||||||
|
|
||||||
initGUI();
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 1", "[]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Broadcast Channel" ), "grow" );
|
|
||||||
|
|
||||||
List<String> channelNames = mBroadcastModel.getBroadcastConfigurationNames();
|
|
||||||
|
|
||||||
mBroadcastConfigurations = new JComboBox<String>(channelNames.toArray(new String[0]));
|
|
||||||
mBroadcastConfigurations.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mBroadcastConfigurations, "grow");
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( BroadcastChannelEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(AliasID item)
|
|
||||||
{
|
|
||||||
super.setItem(item);
|
|
||||||
|
|
||||||
if(item instanceof BroadcastChannel)
|
|
||||||
{
|
|
||||||
BroadcastChannel channel = (BroadcastChannel)item;
|
|
||||||
|
|
||||||
if(channel.isValid())
|
|
||||||
{
|
|
||||||
mBroadcastConfigurations.setSelectedItem(channel.getChannelName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
String channel = (String)mBroadcastConfigurations.getSelectedItem();
|
|
||||||
|
|
||||||
BroadcastConfiguration selectedConfiguration = mBroadcastModel.getBroadcastConfiguration(channel);
|
|
||||||
|
|
||||||
|
|
||||||
if(selectedConfiguration != null)
|
|
||||||
{
|
|
||||||
((BroadcastChannel)getItem()).setChannelName(selectedConfiguration.getName());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
((BroadcastChannel)getItem()).setChannelName(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,113 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.esn;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class ESNEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT =
|
|
||||||
"<html><h3>Electronic Serial Number (ESN)</h3>"
|
|
||||||
+ "<b>ESN:</b> hexadecimal 0-9, A-F (e.g. <u>ABCD1234</u> )<br>"
|
|
||||||
+ "<b>Wildcard:</b> use an asterisk (*) to wildcard individual<br>"
|
|
||||||
+ "digits (e.g. <u>ABCD123*</u> or <u>AB**1**4</u>)"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public ESNEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "ESN:" ) );
|
|
||||||
mTextField = new JTextField();
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( ESNEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Esn getEsn()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof Esn )
|
|
||||||
{
|
|
||||||
return (Esn)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
Esn esn = getEsn();
|
|
||||||
|
|
||||||
if( esn != null )
|
|
||||||
{
|
|
||||||
mTextField.setText( esn.getEsn() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
Esn esn = getEsn();
|
|
||||||
|
|
||||||
if( esn != null )
|
|
||||||
{
|
|
||||||
esn.setEsn( mTextField.getText() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,12 @@ public class Esn extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "esn")
|
@JacksonXmlProperty(isAttribute = true, localName = "esn")
|
||||||
public String getEsn()
|
public String getEsn()
|
||||||
{
|
{
|
||||||
@@ -44,6 +50,7 @@ public class Esn extends AliasID
|
|||||||
public void setEsn(String esn )
|
public void setEsn(String esn )
|
||||||
{
|
{
|
||||||
mEsn = esn;
|
mEsn = esn;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
|
|||||||
@@ -31,6 +31,12 @@ public class FleetsyncID extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "ident")
|
@JacksonXmlProperty(isAttribute = true, localName = "ident")
|
||||||
public String getIdent()
|
public String getIdent()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,137 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.fleetsync;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.JFormattedTextField;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class FleetsyncIDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger( FleetsyncIDEditor.class );
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Fleetsync Identifier</h3>"
|
|
||||||
+ "<b>Fleetsync:</b> ggg-uuuu where g=Group and u=Unit (e.g. <u>001-0001</u>)<br>"
|
|
||||||
+ "<b>Wildcard:</b> use an asterisk (*) for each digit (e.g. <u>001-****</u>)"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public FleetsyncIDEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Fleetsync ID:" ) );
|
|
||||||
|
|
||||||
MaskFormatter formatter = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Mask: 3 digits - 4 digits
|
|
||||||
formatter = new MaskFormatter( "###-####" );
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
//Do nothing, the mask was invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
mTextField = new JFormattedTextField( formatter );
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( FleetsyncIDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public FleetsyncID getFleetsyncID()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof FleetsyncID )
|
|
||||||
{
|
|
||||||
return (FleetsyncID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
FleetsyncID fleetsync = getFleetsyncID();
|
|
||||||
|
|
||||||
if( fleetsync != null )
|
|
||||||
{
|
|
||||||
mTextField.setText( fleetsync.getIdent() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
FleetsyncID fleetsync = getFleetsyncID();
|
|
||||||
|
|
||||||
if( fleetsync != null )
|
|
||||||
{
|
|
||||||
fleetsync.setIdent( mTextField.getText() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,6 +32,12 @@ public class MDC1200ID extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "ident")
|
@JacksonXmlProperty(isAttribute = true, localName = "ident")
|
||||||
public String getIdent()
|
public String getIdent()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,133 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.mdc;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.JFormattedTextField;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class MDC1200IDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>MDC-1200 Identifier</h3>"
|
|
||||||
+ "<b>MDC-1200:</b> four digit [0-9] value (e.g. <u>1234</u>)<br>"
|
|
||||||
+ "<b>Wildcard:</b> use an asterisk (*) to wildcard individual<br>"
|
|
||||||
+ "digits (e.g. <u>123*</u> or <u>**34</u>)"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public MDC1200IDEditor(AliasID aliasID)
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem(aliasID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[right][left]", "[][]"));
|
|
||||||
|
|
||||||
add(new JLabel("MDC-1200 ID:"));
|
|
||||||
|
|
||||||
MaskFormatter formatter = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Mask: 4 digits
|
|
||||||
formatter = new MaskFormatter("####");
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, the mask was invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
mTextField = new JFormattedTextField(formatter);
|
|
||||||
mTextField.getDocument().addDocumentListener(this);
|
|
||||||
mTextField.setToolTipText(HELP_TEXT);
|
|
||||||
add(mTextField, "growx,push");
|
|
||||||
|
|
||||||
JLabel help = new JLabel("Help ...");
|
|
||||||
help.setForeground(Color.BLUE.brighter());
|
|
||||||
help.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
||||||
help.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog(MDC1200IDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(help, "align left");
|
|
||||||
}
|
|
||||||
|
|
||||||
public MDC1200ID getMDC1200ID()
|
|
||||||
{
|
|
||||||
if(getItem() instanceof MDC1200ID)
|
|
||||||
{
|
|
||||||
return (MDC1200ID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(AliasID aliasID)
|
|
||||||
{
|
|
||||||
super.setItem(aliasID);
|
|
||||||
|
|
||||||
MDC1200ID mdc = getMDC1200ID();
|
|
||||||
|
|
||||||
if(mdc != null)
|
|
||||||
{
|
|
||||||
mTextField.setText(mdc.getIdent());
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
MDC1200ID mdc = getMDC1200ID();
|
|
||||||
|
|
||||||
if(mdc != null)
|
|
||||||
{
|
|
||||||
mdc.setIdent(mTextField.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.mobileID;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class MINEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Passport Mobile ID (MIN)</h3>"
|
|
||||||
+ "<b>MIN:</b> six character hex value (e.g. <u>AB12CD</u>)<br>"
|
|
||||||
+ "<b>Wildcard:</b> use an asterisk (*) to wildcard individual<br>"
|
|
||||||
+ "digits (e.g. <u>AB**CD</u> or <u>AB12**</u>)"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public MINEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "MIN:" ) );
|
|
||||||
|
|
||||||
MaskFormatter formatter = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Mask: 6 hex characters
|
|
||||||
formatter = new MaskFormatter( "HHHHHH" );
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
//Do nothing, the mask was invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
mTextField = new JFormattedTextField( formatter );
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( MINEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Min getMin()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof Min )
|
|
||||||
{
|
|
||||||
return (Min)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
Min min = getMin();
|
|
||||||
|
|
||||||
if( min != null )
|
|
||||||
{
|
|
||||||
mTextField.setText( min.getMin() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
Min min = getMin();
|
|
||||||
|
|
||||||
if( min != null )
|
|
||||||
{
|
|
||||||
min.setMin( mTextField.getText() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,6 +33,12 @@ public class Min extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "min")
|
@JacksonXmlProperty(isAttribute = true, localName = "min")
|
||||||
public String getMin()
|
public String getMin()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ public class MPT1327ID extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "ident")
|
@JacksonXmlProperty(isAttribute = true, localName = "ident")
|
||||||
public String getIdent()
|
public String getIdent()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.mpt1327;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.JFormattedTextField;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class MPT1327IDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>MPT-1327 Identifier</h3>"
|
|
||||||
+ "<b>MPT-1327:</b> decimal (0-9) format ppp-iiii where<br>"
|
|
||||||
+ "p=Prefix and i=Ident (e.g. <u>123-0001</u>)<br>"
|
|
||||||
+ "<b>Wildcard:</b> use an asterisk (*) to wildcard individual<br>"
|
|
||||||
+ "digits (e.g. <u>ABCD123*</u> or <u>AB**1**4</u>)"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public MPT1327IDEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "MPT-1327 ID:" ) );
|
|
||||||
|
|
||||||
MaskFormatter formatter = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Mask: 3 digits - 4 digits
|
|
||||||
formatter = new MaskFormatter( "***-****" );
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
//Do nothing, the mask was invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
mTextField = new JFormattedTextField( formatter );
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( MPT1327IDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public MPT1327ID getMPT1327ID()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof MPT1327ID )
|
|
||||||
{
|
|
||||||
return (MPT1327ID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
MPT1327ID mpt = getMPT1327ID();
|
|
||||||
|
|
||||||
if( mpt != null )
|
|
||||||
{
|
|
||||||
mTextField.setText( mpt.getIdent() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
MPT1327ID mpt = getMPT1327ID();
|
|
||||||
|
|
||||||
if( mpt != null )
|
|
||||||
{
|
|
||||||
mpt.setIdent( mTextField.getText() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -33,6 +33,12 @@ public class NonRecordable extends AliasID
|
|||||||
return AliasIDType.NON_RECORDABLE;
|
return AliasIDType.NON_RECORDABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid()
|
public boolean isValid()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.nonrecordable;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class NonRecordableEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Audio Non-Recordable</h3>"
|
|
||||||
+ "This identifies an alias as non-recordable.<br><br>"
|
|
||||||
+ "The alias can still be monitored but associated audio will<br>"
|
|
||||||
+ "not be recorded.<br><br>"
|
|
||||||
+ "The default behavior when audio recording is enabled for a<br>"
|
|
||||||
+ "channel is to record all aliases except any alias with a<br>"
|
|
||||||
+ "non-recordable identifier";
|
|
||||||
|
|
||||||
public NonRecordableEditor(AliasID aliasID)
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem(aliasID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 1", "[]", "[][]"));
|
|
||||||
|
|
||||||
add(new JLabel("Non-Recordable"), "wrap");
|
|
||||||
|
|
||||||
JLabel help = new JLabel("Help ...");
|
|
||||||
help.setForeground(Color.BLUE.brighter());
|
|
||||||
help.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
||||||
help.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog(NonRecordableEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(help, "align left");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,12 @@ public class SiteID extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "site")
|
@JacksonXmlProperty(isAttribute = true, localName = "site")
|
||||||
public String getSite()
|
public String getSite()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,116 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.siteID;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class SiteIDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Site Identifier</h3>"
|
|
||||||
+ "<b>LTR-Net:</b> decimal (0-9) (e.g. <u>019</u>)<br>"
|
|
||||||
+ "<b>MPT-1327:</b> 5 digits (0-9) (e.g. <u>23619</u>)<br>"
|
|
||||||
+ "<b>Passport:</b> 3 digits (0-9) (e.g. <u>019</u>)<br>"
|
|
||||||
+ "<b>P25:</b> hex (0-9, A-F) format RR-SS where RR = RF Subsystem<br>"
|
|
||||||
+ "and SS = Site Number (e.g. RFSS 1 Site 1F: <u>01-1F</u>)"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public SiteIDEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Site ID:" ) );
|
|
||||||
mTextField = new JTextField();
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( SiteIDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public SiteID getSiteID()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof SiteID )
|
|
||||||
{
|
|
||||||
return (SiteID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
SiteID siteID = getSiteID();
|
|
||||||
|
|
||||||
if( siteID != null )
|
|
||||||
{
|
|
||||||
mTextField.setText( siteID.getSite() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
SiteID siteID = getSiteID();
|
|
||||||
|
|
||||||
if( siteID != null )
|
|
||||||
{
|
|
||||||
siteID.setSite( mTextField.getText() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -38,6 +38,12 @@ public class LegacyTalkgroupID extends AliasID
|
|||||||
mTalkgroup = talkgroup;
|
mTalkgroup = talkgroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "talkgroup")
|
@JacksonXmlProperty(isAttribute = true, localName = "talkgroup")
|
||||||
public String getTalkgroup()
|
public String getTalkgroup()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,121 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.talkgroup;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class LegacyTalkgroupIDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT =
|
|
||||||
"<html><h3>Talkgroup Identifier</h3>"
|
|
||||||
+ "<b>P25:</b> 4 or 6 hex characters (e.g. <u>AB12</u> or <u>ABC123</u>)<br>"
|
|
||||||
+ "<b>LTR:</b> A-HH-TTT where A=Area H=Home T=Talkgroup (<u>0-01-128</u>)<br>"
|
|
||||||
+ "<b>Passport</b>: 5-digit number (<u>12345</u> or <u>00023</u>)<br>"
|
|
||||||
+ "<br>"
|
|
||||||
+ "<b>Wildcard:</b> use an asterisk (*) in place of each talkgroup digit (e.g. <u>0*1*5</u>)"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public LegacyTalkgroupIDEditor(AliasID aliasID)
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem(aliasID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[right][left]", "[][]"));
|
|
||||||
|
|
||||||
add(new JLabel("Talkgroup:"));
|
|
||||||
|
|
||||||
mTextField = new JTextField();
|
|
||||||
mTextField.getDocument().addDocumentListener(this);
|
|
||||||
mTextField.setToolTipText(HELP_TEXT);
|
|
||||||
add(mTextField, "growx,push");
|
|
||||||
|
|
||||||
JLabel help = new JLabel("Help ...");
|
|
||||||
help.setForeground(Color.BLUE.brighter());
|
|
||||||
help.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
||||||
help.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog(LegacyTalkgroupIDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(help, "align left");
|
|
||||||
}
|
|
||||||
|
|
||||||
public LegacyTalkgroupID getTalkgroupID()
|
|
||||||
{
|
|
||||||
if(getItem() instanceof LegacyTalkgroupID)
|
|
||||||
{
|
|
||||||
return (LegacyTalkgroupID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(AliasID aliasID)
|
|
||||||
{
|
|
||||||
super.setItem(aliasID);
|
|
||||||
|
|
||||||
LegacyTalkgroupID talkgroup = getTalkgroupID();
|
|
||||||
|
|
||||||
if(talkgroup != null)
|
|
||||||
{
|
|
||||||
mTextField.setText(talkgroup.getTalkgroup());
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
LegacyTalkgroupID talkgroup = getTalkgroupID();
|
|
||||||
|
|
||||||
if(talkgroup != null)
|
|
||||||
{
|
|
||||||
talkgroup.setTalkgroup(mTextField.getText());
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,6 +29,12 @@ public class UniqueID extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "uid")
|
@JacksonXmlProperty(isAttribute = true, localName = "uid")
|
||||||
public int getUid()
|
public int getUid()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,123 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.legacy.uniqueID;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class UniqueIDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>LTR-Net Unique ID (UID)</h3>"
|
|
||||||
+ "<b>UID:</b> identifier assigned to each radio in<br>"
|
|
||||||
+ "the range <u>1 - 2097152</u>"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public UniqueIDEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Unique ID:" ) );
|
|
||||||
mTextField = new JTextField();
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( UniqueIDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public UniqueID getUniqueID()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof UniqueID )
|
|
||||||
{
|
|
||||||
return (UniqueID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
UniqueID uid = getUniqueID();
|
|
||||||
|
|
||||||
if( uid != null )
|
|
||||||
{
|
|
||||||
mTextField.setText( String.valueOf( uid.getUid() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
UniqueID uid = getUniqueID();
|
|
||||||
|
|
||||||
if( uid != null )
|
|
||||||
{
|
|
||||||
int id = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
id = Integer.parseInt( mTextField.getText() );
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the value
|
|
||||||
}
|
|
||||||
|
|
||||||
uid.setUid( id );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,6 +32,12 @@ public class LoJackFunctionAndID extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "id")
|
@JacksonXmlProperty(isAttribute = true, localName = "id")
|
||||||
public String getID()
|
public String getID()
|
||||||
{
|
{
|
||||||
@@ -41,6 +47,7 @@ public class LoJackFunctionAndID extends AliasID
|
|||||||
public void setID(String id)
|
public void setID(String id)
|
||||||
{
|
{
|
||||||
mID = id;
|
mID = id;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "function")
|
@JacksonXmlProperty(isAttribute = true, localName = "function")
|
||||||
@@ -52,6 +59,7 @@ public class LoJackFunctionAndID extends AliasID
|
|||||||
public void setFunction(LJ1200Message.Function function)
|
public void setFunction(LJ1200Message.Function function)
|
||||||
{
|
{
|
||||||
mFunction = function;
|
mFunction = function;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,160 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.lojack;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import io.github.dsheirer.module.decode.lj1200.LJ1200Message;
|
|
||||||
import io.github.dsheirer.module.decode.lj1200.LJ1200Message.Function;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class LoJackIDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
private JComboBox<LJ1200Message.Function> mFunctionCombo;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>LoJack Function and Identifier</h3>"
|
|
||||||
+ "<b>Function Code:</b> <u>1Y-SITE ID</u><br>"
|
|
||||||
+ "<b>ID:</b> 5 numbers or characters (e.g. <u>1BN47</u>)<br>"
|
|
||||||
+ "<br>"
|
|
||||||
+ "<b>Wildcard:</b> use an asterisk (*) to wildcard ID<br>"
|
|
||||||
+ "characters (e.g. <u>AB*CD</u> or <u>***12</u> or <u>*****</u>)<br><br>"
|
|
||||||
+ "The middle character in a reply ID code identifies the<br>"
|
|
||||||
+ "entity. Valid ID middle characters are:<br>"
|
|
||||||
+ "<li><b>Tower:</b> X,Y</li>"
|
|
||||||
+ "<li><b>Transponder:</b> 0-9,A,C-H,J-N,P-W</li>"
|
|
||||||
+ "<li><b>Not Used:</b> B,I,O,Z</li>"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
public LoJackIDEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Function:" ) );
|
|
||||||
mFunctionCombo = new JComboBox<LJ1200Message.Function>( Function.values() );
|
|
||||||
mFunctionCombo.addActionListener( new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed( ActionEvent e )
|
|
||||||
{
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
mFunctionCombo.setToolTipText( HELP_TEXT );
|
|
||||||
add( mFunctionCombo, "growx, push" );
|
|
||||||
|
|
||||||
add( new JLabel( "ID:" ) );
|
|
||||||
|
|
||||||
MaskFormatter formatter = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Mask: any character or number, 5 places
|
|
||||||
formatter = new MaskFormatter( "AAAAA" );
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
//Do nothing, the mask was invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
mTextField = new JFormattedTextField( formatter );
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( LoJackIDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public LoJackFunctionAndID getLoJackID()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof LoJackFunctionAndID )
|
|
||||||
{
|
|
||||||
return (LoJackFunctionAndID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
LoJackFunctionAndID lojack = getLoJackID();
|
|
||||||
|
|
||||||
if( lojack != null )
|
|
||||||
{
|
|
||||||
mFunctionCombo.setSelectedItem( lojack.getFunction() );
|
|
||||||
mTextField.setText( lojack.getID() );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mFunctionCombo.setSelectedItem( null );
|
|
||||||
mTextField.setText( null );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
LoJackFunctionAndID lojack = getLoJackID();
|
|
||||||
|
|
||||||
if( lojack != null )
|
|
||||||
{
|
|
||||||
lojack.setID( mTextField.getText() );
|
|
||||||
lojack.setFunction( (Function)mFunctionCombo.getSelectedItem() );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -39,6 +39,17 @@ public class Priority extends AliasID
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Priority(int priority)
|
||||||
|
{
|
||||||
|
mPriority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid()
|
public boolean isValid()
|
||||||
{
|
{
|
||||||
@@ -63,6 +74,7 @@ public class Priority extends AliasID
|
|||||||
public void setPriority(int priority)
|
public void setPriority(int priority)
|
||||||
{
|
{
|
||||||
mPriority = priority;
|
mPriority = priority;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
|
|||||||
@@ -1,163 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.priority;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class PriorityEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
public static final String DO_NOT_MONITOR = "Do Not Monitor";
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Call Audio Priority</h3>"
|
|
||||||
+ "Priority determines which calls have priority for playback<br>"
|
|
||||||
+ "over your computer speakers, or designates an alias for<br>"
|
|
||||||
+ "no-monitoring if you don't want to hear calls from an alias.<br><br>"
|
|
||||||
+ "Lower values indicate higher priority levels.<br><br>"
|
|
||||||
+ "<b>Do Not Monitor: </b> slide priority all the way to the right"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JSlider mPrioritySlider;
|
|
||||||
private JLabel mPrioritySliderLabel;
|
|
||||||
|
|
||||||
public PriorityEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
mPrioritySlider = new JSlider( JSlider.HORIZONTAL,
|
|
||||||
Priority.MIN_PRIORITY,
|
|
||||||
Priority.MAX_PRIORITY + 1,
|
|
||||||
Priority.MIN_PRIORITY );
|
|
||||||
|
|
||||||
mPrioritySlider.setMajorTickSpacing( 20 );
|
|
||||||
mPrioritySlider.setMinorTickSpacing( 5 );
|
|
||||||
mPrioritySlider.setPaintTicks( true );
|
|
||||||
mPrioritySlider.setLabelTable( mPrioritySlider.createStandardLabels( 20, 20 ) );
|
|
||||||
mPrioritySlider.setPaintLabels( true );
|
|
||||||
mPrioritySlider.addChangeListener( new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged( ChangeEvent e )
|
|
||||||
{
|
|
||||||
int priority = mPrioritySlider.getValue();
|
|
||||||
|
|
||||||
if( priority == Priority.MAX_PRIORITY + 1 )
|
|
||||||
{
|
|
||||||
mPrioritySliderLabel.setText( "Priority: Do Not Monitor" );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mPrioritySliderLabel.setText( "Priority: " + priority );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( true );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
mPrioritySlider.setToolTipText( HELP_TEXT );
|
|
||||||
|
|
||||||
mPrioritySliderLabel = new JLabel( "Priority: " + mPrioritySlider.getValue() + " " );
|
|
||||||
add( mPrioritySliderLabel, "span,align center" );
|
|
||||||
add( mPrioritySlider, "span,grow" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( PriorityEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public Priority getPriority()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof Priority )
|
|
||||||
{
|
|
||||||
return (Priority)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
Priority priority = getPriority();
|
|
||||||
|
|
||||||
if( priority != null )
|
|
||||||
{
|
|
||||||
int value = priority.getPriority();
|
|
||||||
|
|
||||||
if( value == Priority.DO_NOT_MONITOR )
|
|
||||||
{
|
|
||||||
value = Priority.MAX_PRIORITY + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
mPrioritySlider.setValue( value );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
Priority priority = getPriority();
|
|
||||||
|
|
||||||
if( priority != null )
|
|
||||||
{
|
|
||||||
int value = mPrioritySlider.getValue();
|
|
||||||
|
|
||||||
if( value == Priority.MAX_PRIORITY + 1 )
|
|
||||||
{
|
|
||||||
value = Priority.DO_NOT_MONITOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
priority.setPriority( value );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,14 +25,13 @@ package io.github.dsheirer.alias.id.radio;
|
|||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
import io.github.dsheirer.alias.id.AliasID;
|
||||||
import io.github.dsheirer.alias.id.AliasIDType;
|
import io.github.dsheirer.alias.id.AliasIDType;
|
||||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupFormat;
|
|
||||||
import io.github.dsheirer.alias.id.talkgroup.TalkgroupFormatter;
|
import io.github.dsheirer.alias.id.talkgroup.TalkgroupFormatter;
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
import io.github.dsheirer.protocol.Protocol;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integer radio identifier with protocol.
|
* Integer radio identifier with protocol.
|
||||||
*/
|
*/
|
||||||
public class Radio extends AliasID
|
public class Radio extends AliasID implements Comparable<Radio>
|
||||||
{
|
{
|
||||||
private Protocol mProtocol = Protocol.UNKNOWN;
|
private Protocol mProtocol = Protocol.UNKNOWN;
|
||||||
private int mValue;
|
private int mValue;
|
||||||
@@ -48,6 +47,12 @@ public class Radio extends AliasID
|
|||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "value")
|
@JacksonXmlProperty(isAttribute = true, localName = "value")
|
||||||
public int getValue()
|
public int getValue()
|
||||||
{
|
{
|
||||||
@@ -57,6 +62,7 @@ public class Radio extends AliasID
|
|||||||
public void setValue(int value)
|
public void setValue(int value)
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
||||||
@@ -68,6 +74,7 @@ public class Radio extends AliasID
|
|||||||
public void setProtocol(Protocol protocol)
|
public void setProtocol(Protocol protocol)
|
||||||
{
|
{
|
||||||
mProtocol = protocol;
|
mProtocol = protocol;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -115,4 +122,22 @@ public class Radio extends AliasID
|
|||||||
{
|
{
|
||||||
return AliasIDType.RADIO_ID;
|
return AliasIDType.RADIO_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Radio other)
|
||||||
|
{
|
||||||
|
if(other == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getProtocol().equals(other.getProtocol()))
|
||||||
|
{
|
||||||
|
return Integer.compare(getValue(), other.getValue());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return getProtocol().compareTo(other.getProtocol());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,235 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * ******************************************************************************
|
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
* *
|
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
|
||||||
* * it under the terms of the GNU General Public License as published by
|
|
||||||
* * the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* * (at your option) any later version.
|
|
||||||
* *
|
|
||||||
* * This program is distributed in the hope that it will be useful,
|
|
||||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* * GNU General Public License for more details.
|
|
||||||
* *
|
|
||||||
* * You should have received a copy of the GNU General Public License
|
|
||||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* * *****************************************************************************
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.radio;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JFormattedTextField;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.text.ParseException;
|
|
||||||
|
|
||||||
public class RadioEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(RadioEditor.class);
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String VALID_CHARACTERS_FOR_ASTERISK_MASKS = "0123456789 ";
|
|
||||||
private MaskFormatter mMaskFormatter = new MaskFormatter();
|
|
||||||
private JComboBox<Protocol> mComboProtocol;
|
|
||||||
private JFormattedTextField mRadioIdField;
|
|
||||||
|
|
||||||
|
|
||||||
public RadioEditor(AliasID aliasID)
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
setItem(aliasID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[right][left]", "[][]"));
|
|
||||||
|
|
||||||
add(new JLabel("Protocol:"));
|
|
||||||
|
|
||||||
mComboProtocol = new JComboBox<>();
|
|
||||||
|
|
||||||
DefaultComboBoxModel<Protocol> model = new DefaultComboBoxModel<>();
|
|
||||||
|
|
||||||
for(Protocol protocol : Protocol.RADIO_ID_PROTOCOLS)
|
|
||||||
{
|
|
||||||
model.addElement(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
mComboProtocol.setModel(model);
|
|
||||||
mComboProtocol.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
Protocol protocol = (Protocol)mComboProtocol.getSelectedItem();
|
|
||||||
updateEditor(protocol);
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mComboProtocol);
|
|
||||||
|
|
||||||
add(new JLabel("Value:"));
|
|
||||||
|
|
||||||
mRadioIdField = new JFormattedTextField(mMaskFormatter);
|
|
||||||
mRadioIdField.getDocument().addDocumentListener(this);
|
|
||||||
add(mRadioIdField, "growx,push");
|
|
||||||
|
|
||||||
JLabel help = new JLabel("Help ...");
|
|
||||||
help.setForeground(Color.BLUE.brighter());
|
|
||||||
help.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
||||||
help.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
RadioFormat radioFormat = RadioFormat.get(getCurrentProtocol());
|
|
||||||
JOptionPane.showMessageDialog(RadioEditor.this,
|
|
||||||
radioFormat.getValidRangeHelpText(), "Help", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(help, "align left");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateEditor(Protocol protocol)
|
|
||||||
{
|
|
||||||
RadioFormat mask = RadioFormat.get(protocol);
|
|
||||||
int currentValue = 0;
|
|
||||||
Radio radio = getRadio();
|
|
||||||
|
|
||||||
if(radio != null)
|
|
||||||
{
|
|
||||||
currentValue = radio.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mRadioIdField.setValue(null);
|
|
||||||
mRadioIdField.setToolTipText(mask.getValidRangeHelpText());
|
|
||||||
mMaskFormatter.setMask(mask.getMask());
|
|
||||||
if(mask.getMask().contains("*"))
|
|
||||||
{
|
|
||||||
mMaskFormatter.setValidCharacters(VALID_CHARACTERS_FOR_ASTERISK_MASKS);
|
|
||||||
}
|
|
||||||
mRadioIdField.setValue(RadioFormatter.format(protocol, currentValue));
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
mLog.error("Error applying talkgroup editor mask to mask formatter [" + mask.getMask() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Protocol getCurrentProtocol()
|
|
||||||
{
|
|
||||||
return mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current talkgroup alias id
|
|
||||||
*/
|
|
||||||
public Radio getRadio()
|
|
||||||
{
|
|
||||||
if(getItem() instanceof Radio)
|
|
||||||
{
|
|
||||||
return (Radio)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(AliasID aliasID)
|
|
||||||
{
|
|
||||||
super.setItem(aliasID);
|
|
||||||
|
|
||||||
Radio radio = getRadio();
|
|
||||||
|
|
||||||
if(radio != null)
|
|
||||||
{
|
|
||||||
Protocol currentProtocol = getCurrentProtocol();
|
|
||||||
if(currentProtocol == radio.getProtocol())
|
|
||||||
{
|
|
||||||
updateEditor(radio.getProtocol());
|
|
||||||
}
|
|
||||||
mComboProtocol.getModel().setSelectedItem(radio.getProtocol());
|
|
||||||
|
|
||||||
String formatted = RadioFormatter.format(radio.getProtocol(), radio.getValue());
|
|
||||||
mRadioIdField.setValue(formatted);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mComboProtocol.getModel().setSelectedItem(Protocol.UNKNOWN);
|
|
||||||
mRadioIdField.setValue(RadioFormatter.format(getCurrentProtocol(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
Radio radio = getRadio();
|
|
||||||
|
|
||||||
if(radio != null)
|
|
||||||
{
|
|
||||||
Protocol protocol = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
|
|
||||||
if(protocol == null)
|
|
||||||
{
|
|
||||||
protocol = Protocol.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
int value = -1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
value = RadioFormatter.parse(protocol, mRadioIdField.getText());
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
//ignore ... value is still -1 and outside valid value range
|
|
||||||
}
|
|
||||||
|
|
||||||
RadioFormat mask = RadioFormat.get(protocol);
|
|
||||||
|
|
||||||
//Check for valid value within range ... notify user but allow value to persist
|
|
||||||
if(value < mask.getMinimumValidValue() || value > mask.getMaximumValidValue())
|
|
||||||
{
|
|
||||||
String message = "Invalid value [" + mRadioIdField.getText() + "]. " + protocol.name() +
|
|
||||||
" valid range is [" + mask.getValidRangeDescription() + "]";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(RadioEditor.this, message, "Invalid Radio ID Value",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
radio.setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
radio.setProtocol(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -36,6 +36,8 @@ public enum RadioFormat
|
|||||||
{
|
{
|
||||||
APCO25("********", 0, 0xFFFFFF, "0 to 16,777,215",
|
APCO25("********", 0, 0xFFFFFF, "0 to 16,777,215",
|
||||||
"<html>APCO25 valid range is 0 to 16,777,215"),
|
"<html>APCO25 valid range is 0 to 16,777,215"),
|
||||||
|
PASSPORT("********", 0, 0x7FFFFF, "0 to 8,388,607",
|
||||||
|
"<html>PASSPORT valid range is 0 to 8,388,607"),
|
||||||
UNKNOWN("********", 1, 0xFFFFFF, "1 to 16,777,215",
|
UNKNOWN("********", 1, 0xFFFFFF, "1 to 16,777,215",
|
||||||
"Unknown protocol valid value range is 1-16,777,215");
|
"Unknown protocol valid value range is 1-16,777,215");
|
||||||
|
|
||||||
@@ -110,6 +112,8 @@ public enum RadioFormat
|
|||||||
{
|
{
|
||||||
case APCO25:
|
case APCO25:
|
||||||
return APCO25;
|
return APCO25;
|
||||||
|
case PASSPORT:
|
||||||
|
return PASSPORT;
|
||||||
default:
|
default:
|
||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,10 @@
|
|||||||
|
|
||||||
package io.github.dsheirer.alias.id.radio;
|
package io.github.dsheirer.alias.id.radio;
|
||||||
|
|
||||||
|
import io.github.dsheirer.preference.identifier.IntegerFormat;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.APCO25TalkgroupFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.APCO25TalkgroupFormatter;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.IntegerFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.AbstractIntegerFormatter;
|
||||||
|
import io.github.dsheirer.preference.identifier.talkgroup.UnknownTalkgroupFormatter;
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
import io.github.dsheirer.protocol.Protocol;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -39,12 +41,12 @@ import java.util.Map;
|
|||||||
public class RadioFormatter
|
public class RadioFormatter
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(RadioFormatter.class);
|
private final static Logger mLog = LoggerFactory.getLogger(RadioFormatter.class);
|
||||||
private static Map<Protocol,IntegerFormatter> mFormatterMap = new EnumMap<>(Protocol.class);
|
private static Map<Protocol,AbstractIntegerFormatter> mFormatterMap = new EnumMap<>(Protocol.class);
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
mFormatterMap.put(Protocol.APCO25, new APCO25TalkgroupFormatter());
|
mFormatterMap.put(Protocol.APCO25, new APCO25TalkgroupFormatter());
|
||||||
mFormatterMap.put(Protocol.UNKNOWN, new IntegerFormatter());
|
mFormatterMap.put(Protocol.UNKNOWN, new UnknownTalkgroupFormatter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public RadioFormatter()
|
public RadioFormatter()
|
||||||
@@ -56,7 +58,7 @@ public class RadioFormatter
|
|||||||
*/
|
*/
|
||||||
public static int parse(Protocol protocol, String value) throws ParseException
|
public static int parse(Protocol protocol, String value) throws ParseException
|
||||||
{
|
{
|
||||||
IntegerFormatter formatter = mFormatterMap.get(protocol);
|
AbstractIntegerFormatter formatter = mFormatterMap.get(protocol);
|
||||||
|
|
||||||
if(formatter == null)
|
if(formatter == null)
|
||||||
{
|
{
|
||||||
@@ -71,7 +73,7 @@ public class RadioFormatter
|
|||||||
*/
|
*/
|
||||||
public static String format(Protocol protocol, int value)
|
public static String format(Protocol protocol, int value)
|
||||||
{
|
{
|
||||||
IntegerFormatter formatter = mFormatterMap.get(protocol);
|
AbstractIntegerFormatter formatter = mFormatterMap.get(protocol);
|
||||||
|
|
||||||
if(formatter == null)
|
if(formatter == null)
|
||||||
{
|
{
|
||||||
@@ -80,4 +82,19 @@ public class RadioFormatter
|
|||||||
|
|
||||||
return formatter.format(value);
|
return formatter.format(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the integer value to the specified integer format using the protocol specific formatter
|
||||||
|
*/
|
||||||
|
public static String format(Protocol protocol, int value, IntegerFormat format)
|
||||||
|
{
|
||||||
|
AbstractIntegerFormatter formatter = mFormatterMap.get(protocol);
|
||||||
|
|
||||||
|
if(formatter == null)
|
||||||
|
{
|
||||||
|
formatter = mFormatterMap.get(Protocol.UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatter.format(value, format);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import io.github.dsheirer.protocol.Protocol;
|
|||||||
/**
|
/**
|
||||||
* Integer radio identifier range of values with protocol.
|
* Integer radio identifier range of values with protocol.
|
||||||
*/
|
*/
|
||||||
public class RadioRange extends AliasID
|
public class RadioRange extends AliasID implements Comparable<RadioRange>
|
||||||
{
|
{
|
||||||
private Protocol mProtocol = Protocol.UNKNOWN;
|
private Protocol mProtocol = Protocol.UNKNOWN;
|
||||||
private int mMinRadio;
|
private int mMinRadio;
|
||||||
@@ -41,6 +41,12 @@ public class RadioRange extends AliasID
|
|||||||
//No arg JAXB constructor
|
//No arg JAXB constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a radio range of from - to radio values (inclusive) for the specified protocol
|
* Creates a radio range of from - to radio values (inclusive) for the specified protocol
|
||||||
* @param protocol for the radio range
|
* @param protocol for the radio range
|
||||||
@@ -63,6 +69,7 @@ public class RadioRange extends AliasID
|
|||||||
public void setMinRadio(int minRadio)
|
public void setMinRadio(int minRadio)
|
||||||
{
|
{
|
||||||
mMinRadio = minRadio;
|
mMinRadio = minRadio;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "max")
|
@JacksonXmlProperty(isAttribute = true, localName = "max")
|
||||||
@@ -74,6 +81,7 @@ public class RadioRange extends AliasID
|
|||||||
public void setMaxRadio(int maxRadio)
|
public void setMaxRadio(int maxRadio)
|
||||||
{
|
{
|
||||||
mMaxRadio = maxRadio;
|
mMaxRadio = maxRadio;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
||||||
@@ -99,7 +107,8 @@ public class RadioRange extends AliasID
|
|||||||
return radioFormat.getMinimumValidValue() <= mMinRadio &&
|
return radioFormat.getMinimumValidValue() <= mMinRadio &&
|
||||||
mMinRadio <= radioFormat.getMaximumValidValue() &&
|
mMinRadio <= radioFormat.getMaximumValidValue() &&
|
||||||
radioFormat.getMinimumValidValue() <= mMaxRadio &&
|
radioFormat.getMinimumValidValue() <= mMaxRadio &&
|
||||||
mMaxRadio <= radioFormat.getMaximumValidValue();
|
mMaxRadio <= radioFormat.getMaximumValidValue() &&
|
||||||
|
mMinRadio < mMaxRadio;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
@@ -142,6 +151,13 @@ public class RadioRange extends AliasID
|
|||||||
return getMinRadio() <= radioValue && radioValue <= getMaxRadio();
|
return getMinRadio() <= radioValue && radioValue <= getMaxRadio();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean overlaps(AliasID other)
|
||||||
|
{
|
||||||
|
return other instanceof RadioRange && overlaps((RadioRange)other);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if this talkgroup range overlaps the talkgroup range argument.
|
* Indicates if this talkgroup range overlaps the talkgroup range argument.
|
||||||
* @param radioRange to check for overlap
|
* @param radioRange to check for overlap
|
||||||
@@ -163,4 +179,30 @@ public class RadioRange extends AliasID
|
|||||||
{
|
{
|
||||||
return AliasIDType.RADIO_ID_RANGE;
|
return AliasIDType.RADIO_ID_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(RadioRange other)
|
||||||
|
{
|
||||||
|
if(other == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getProtocol().equals(other.getProtocol()))
|
||||||
|
{
|
||||||
|
if(getMinRadio() == other.getMinRadio())
|
||||||
|
{
|
||||||
|
return Integer.compare(getMaxRadio(), other.getMaxRadio());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Integer.compare(getMinRadio(), other.getMinRadio());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return getProtocol().compareTo(other.getProtocol());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,273 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * ******************************************************************************
|
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
* *
|
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
|
||||||
* * it under the terms of the GNU General Public License as published by
|
|
||||||
* * the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* * (at your option) any later version.
|
|
||||||
* *
|
|
||||||
* * This program is distributed in the hope that it will be useful,
|
|
||||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* * GNU General Public License for more details.
|
|
||||||
* *
|
|
||||||
* * You should have received a copy of the GNU General Public License
|
|
||||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* * *****************************************************************************
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.radio;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JFormattedTextField;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.text.ParseException;
|
|
||||||
|
|
||||||
public class RadioRangeEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(RadioRangeEditor.class);
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String VALID_CHARACTERS_FOR_ASTERISK_MASKS = "0123456789 ";
|
|
||||||
private MaskFormatter mMaskFormatter = new MaskFormatter();
|
|
||||||
private JComboBox<Protocol> mComboProtocol;
|
|
||||||
private JFormattedTextField mMinRadioField;
|
|
||||||
private JFormattedTextField mMaxRadioField;
|
|
||||||
|
|
||||||
public RadioRangeEditor(AliasID aliasID)
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem(aliasID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[right][left]", "[][]"));
|
|
||||||
|
|
||||||
add(new JLabel("Protocol:"));
|
|
||||||
|
|
||||||
mComboProtocol = new JComboBox<Protocol>();
|
|
||||||
|
|
||||||
DefaultComboBoxModel<Protocol> model = new DefaultComboBoxModel<>();
|
|
||||||
|
|
||||||
for(Protocol protocol : Protocol.RADIO_ID_PROTOCOLS)
|
|
||||||
{
|
|
||||||
model.addElement(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
mComboProtocol.setModel(model);
|
|
||||||
mComboProtocol.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
Protocol protocol = (Protocol)mComboProtocol.getSelectedItem();
|
|
||||||
updateEditor(protocol);
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mComboProtocol);
|
|
||||||
|
|
||||||
add(new JLabel("Min:"));
|
|
||||||
|
|
||||||
mMinRadioField = new JFormattedTextField(mMaskFormatter);
|
|
||||||
mMinRadioField.getDocument().addDocumentListener(this);
|
|
||||||
add(mMinRadioField, "growx,push");
|
|
||||||
|
|
||||||
add(new JLabel("Max:"));
|
|
||||||
|
|
||||||
mMaxRadioField = new JFormattedTextField(mMaskFormatter);
|
|
||||||
mMaxRadioField.getDocument().addDocumentListener(this);
|
|
||||||
add(mMaxRadioField, "growx,push");
|
|
||||||
|
|
||||||
JLabel help = new JLabel("Help ...");
|
|
||||||
help.setForeground(Color.BLUE.brighter());
|
|
||||||
help.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
||||||
help.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
RadioFormat radioFormat = RadioFormat.get(getCurrentProtocol());
|
|
||||||
JOptionPane.showMessageDialog(RadioRangeEditor.this,
|
|
||||||
radioFormat.getValidRangeHelpText(), "Help", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(help, "align left");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateEditor(Protocol protocol)
|
|
||||||
{
|
|
||||||
RadioFormat mask = RadioFormat.get(protocol);
|
|
||||||
int currentMinValue = 0;
|
|
||||||
int currentMaxValue = 0;
|
|
||||||
RadioRange radioRange = getRadioRange();
|
|
||||||
|
|
||||||
if(radioRange != null)
|
|
||||||
{
|
|
||||||
currentMinValue = radioRange.getMinRadio();
|
|
||||||
currentMaxValue = radioRange.getMaxRadio();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mMinRadioField.setValue(null);
|
|
||||||
mMaxRadioField.setValue(null);
|
|
||||||
|
|
||||||
mMinRadioField.setToolTipText(mask.getValidRangeHelpText());
|
|
||||||
mMaxRadioField.setToolTipText(mask.getValidRangeHelpText());
|
|
||||||
mMaskFormatter.setMask(mask.getMask());
|
|
||||||
if(mask.getMask().contains("*"))
|
|
||||||
{
|
|
||||||
mMaskFormatter.setValidCharacters(VALID_CHARACTERS_FOR_ASTERISK_MASKS);
|
|
||||||
}
|
|
||||||
|
|
||||||
mMinRadioField.setValue(RadioFormatter.format(protocol, currentMinValue));
|
|
||||||
mMaxRadioField.setValue(RadioFormatter.format(protocol, currentMaxValue));
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
mLog.error("Error applying radio editor mask to mask formatter [" + mask.getMask() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Protocol getCurrentProtocol()
|
|
||||||
{
|
|
||||||
return mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public RadioRange getRadioRange()
|
|
||||||
{
|
|
||||||
if(getItem() instanceof RadioRange)
|
|
||||||
{
|
|
||||||
return (RadioRange)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(AliasID aliasID)
|
|
||||||
{
|
|
||||||
super.setItem(aliasID);
|
|
||||||
|
|
||||||
RadioRange radioRange = getRadioRange();
|
|
||||||
|
|
||||||
updateEditor(radioRange.getProtocol());
|
|
||||||
|
|
||||||
if(radioRange != null)
|
|
||||||
{
|
|
||||||
mComboProtocol.getModel().setSelectedItem(radioRange.getProtocol());
|
|
||||||
String minFormatted = RadioFormatter.format(radioRange.getProtocol(), radioRange.getMinRadio());
|
|
||||||
mMinRadioField.setValue(minFormatted);
|
|
||||||
String maxFormatted = RadioFormatter.format(radioRange.getProtocol(), radioRange.getMaxRadio());
|
|
||||||
mMaxRadioField.setValue(maxFormatted);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mComboProtocol.getModel().setSelectedItem(Protocol.UNKNOWN);
|
|
||||||
mMinRadioField.setValue(RadioFormatter.format(getCurrentProtocol(), 0));
|
|
||||||
mMaxRadioField.setValue(RadioFormatter.format(getCurrentProtocol(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
RadioRange radioRange = getRadioRange();
|
|
||||||
|
|
||||||
if(radioRange != null)
|
|
||||||
{
|
|
||||||
Protocol protocol = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
|
|
||||||
if(protocol == null)
|
|
||||||
{
|
|
||||||
protocol = Protocol.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
radioRange.setProtocol(protocol);
|
|
||||||
|
|
||||||
int minValue = -1;
|
|
||||||
int maxValue = -1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
minValue = RadioFormatter.parse(protocol, mMinRadioField.getText());
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
//ignore ... value is still -1 and outside valid value range
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
maxValue = RadioFormatter.parse(protocol, mMaxRadioField.getText());
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
//ignore ... value is still -1 and outside valid value range
|
|
||||||
}
|
|
||||||
|
|
||||||
RadioFormat mask = RadioFormat.get(protocol);
|
|
||||||
|
|
||||||
//Check for valid value within range ... notify user but allow value to persist
|
|
||||||
if(minValue < mask.getMinimumValidValue() || minValue > mask.getMaximumValidValue())
|
|
||||||
{
|
|
||||||
String message = "Invalid minimum value [" + mMinRadioField.getText() + "]. " + protocol.name() +
|
|
||||||
" valid range is [" + mask.getValidRangeDescription() + "]";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(RadioRangeEditor.this, message,
|
|
||||||
"Invalid Radio Value", JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
radioRange.setMinRadio(minValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check for valid value within range ... notify user but allow value to persist
|
|
||||||
if(maxValue < mask.getMinimumValidValue() || maxValue > mask.getMaximumValidValue())
|
|
||||||
{
|
|
||||||
String message = "Invalid maximum value [" + mMaxRadioField.getText() + "]. " + protocol.name() +
|
|
||||||
" valid range is [" + mask.getValidRangeDescription() + "]";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(RadioRangeEditor.this, message,
|
|
||||||
"Invalid Radio Value", JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
radioRange.setMaxRadio(maxValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
radioRange.setProtocol(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -36,6 +36,12 @@ public class Record extends AliasID
|
|||||||
return AliasIDType.RECORD;
|
return AliasIDType.RECORD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid()
|
public boolean isValid()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.record;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class RecordEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Record Audio</h3>"
|
|
||||||
+ "Any audio associated with this alias will be recorded.<br><br>";
|
|
||||||
|
|
||||||
public RecordEditor(AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 1", "[]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Record Audio" ), "wrap" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( RecordEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* SDR Trunk
|
|
||||||
* Copyright (C) 2014 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.status;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.alias.id.AliasIDType;
|
|
||||||
|
|
||||||
public class StatusID extends AliasID
|
|
||||||
{
|
|
||||||
private int mStatus;
|
|
||||||
|
|
||||||
public StatusID()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "status")
|
|
||||||
public int getStatus()
|
|
||||||
{
|
|
||||||
return mStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setStatus(int status)
|
|
||||||
{
|
|
||||||
this.mStatus = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return "Status: " + String.format("%03d", mStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matches(AliasID id)
|
|
||||||
{
|
|
||||||
boolean retVal = false;
|
|
||||||
|
|
||||||
if(id instanceof StatusID)
|
|
||||||
{
|
|
||||||
StatusID statusId = (StatusID)id;
|
|
||||||
|
|
||||||
retVal = (mStatus == statusId.getStatus());
|
|
||||||
}
|
|
||||||
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
|
||||||
@Override
|
|
||||||
public AliasIDType getType()
|
|
||||||
{
|
|
||||||
return AliasIDType.STATUS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,140 +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 <http://www.gnu.org/licenses/>
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.alias.id.status;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class StatusIDEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String HELP_TEXT = "<html>"
|
|
||||||
+ "<h3>Status Identifier</h3>"
|
|
||||||
+ "Status numbers are used in some protocols like Fleetsync.<br><br>"
|
|
||||||
+ "The status number is assigned a meaning in the radio. You<br>"
|
|
||||||
+ "can assign a 3 digit status code (use leading zeros) to an<br>"
|
|
||||||
+ "alias where the alias contains the status meaning.<br><br>"
|
|
||||||
+ "<b>Status:</b> <u>001</u> engine start"
|
|
||||||
+ "</html>";
|
|
||||||
|
|
||||||
private JTextField mTextField;
|
|
||||||
|
|
||||||
public StatusIDEditor( AliasID aliasID )
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem( aliasID );
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[right][left]", "[][]" ) );
|
|
||||||
|
|
||||||
add( new JLabel( "Status:" ) );
|
|
||||||
|
|
||||||
MaskFormatter formatter = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//Mask: 3 digits
|
|
||||||
formatter = new MaskFormatter( "###" );
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
//Do nothing, the mask was invalid
|
|
||||||
}
|
|
||||||
|
|
||||||
mTextField = new JFormattedTextField( formatter );
|
|
||||||
mTextField.getDocument().addDocumentListener( this );
|
|
||||||
mTextField.setToolTipText( HELP_TEXT );
|
|
||||||
add( mTextField, "growx,push" );
|
|
||||||
|
|
||||||
JLabel help = new JLabel( "Help ..." );
|
|
||||||
help.setForeground( Color.BLUE.brighter() );
|
|
||||||
help.setCursor( new Cursor( Cursor.HAND_CURSOR ) );
|
|
||||||
help.addMouseListener( new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked( MouseEvent e )
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog( StatusIDEditor.this,
|
|
||||||
HELP_TEXT, "Help", JOptionPane.INFORMATION_MESSAGE );
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
add( help, "align left" );
|
|
||||||
}
|
|
||||||
|
|
||||||
public StatusID getStatusID()
|
|
||||||
{
|
|
||||||
if( getItem() instanceof StatusID )
|
|
||||||
{
|
|
||||||
return (StatusID)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem( AliasID aliasID )
|
|
||||||
{
|
|
||||||
super.setItem( aliasID );
|
|
||||||
|
|
||||||
StatusID statusID = getStatusID();
|
|
||||||
|
|
||||||
if( statusID != null )
|
|
||||||
{
|
|
||||||
mTextField.setText( String.format( "%03d", statusID.getStatus() ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
StatusID statusID = getStatusID();
|
|
||||||
|
|
||||||
if( statusID != null )
|
|
||||||
{
|
|
||||||
int status = 0;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
status = Integer.valueOf( mTextField.getText() );
|
|
||||||
}
|
|
||||||
catch( Exception e )
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the value
|
|
||||||
}
|
|
||||||
|
|
||||||
statusID.setStatus( status );
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified( false );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* *****************************************************************************
|
||||||
|
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
package io.github.dsheirer.alias.id.status;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import io.github.dsheirer.alias.id.AliasID;
|
||||||
|
import io.github.dsheirer.alias.id.AliasIDType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit Status
|
||||||
|
*/
|
||||||
|
public class UnitStatusID extends AliasID
|
||||||
|
{
|
||||||
|
private int mStatus;
|
||||||
|
|
||||||
|
public UnitStatusID()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true, localName = "status")
|
||||||
|
public int getStatus()
|
||||||
|
{
|
||||||
|
return mStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status)
|
||||||
|
{
|
||||||
|
mStatus = status;
|
||||||
|
updateValueProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("Unit Status: ").append(String.format("%03d", mStatus));
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(AliasID id)
|
||||||
|
{
|
||||||
|
boolean retVal = false;
|
||||||
|
|
||||||
|
if(id instanceof UnitStatusID)
|
||||||
|
{
|
||||||
|
UnitStatusID userStatusId = (UnitStatusID)id;
|
||||||
|
|
||||||
|
retVal = (mStatus == userStatusId.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||||
|
@Override
|
||||||
|
public AliasIDType getType()
|
||||||
|
{
|
||||||
|
return AliasIDType.UNIT_STATUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* *****************************************************************************
|
||||||
|
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
package io.github.dsheirer.alias.id.status;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
|
import io.github.dsheirer.alias.id.AliasID;
|
||||||
|
import io.github.dsheirer.alias.id.AliasIDType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Status
|
||||||
|
*/
|
||||||
|
public class UserStatusID extends AliasID
|
||||||
|
{
|
||||||
|
private int mStatus;
|
||||||
|
|
||||||
|
public UserStatusID()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true, localName = "status")
|
||||||
|
public int getStatus()
|
||||||
|
{
|
||||||
|
return mStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStatus(int status)
|
||||||
|
{
|
||||||
|
mStatus = status;
|
||||||
|
updateValueProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("User Status: ").append(String.format("%03d", mStatus));
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matches(AliasID id)
|
||||||
|
{
|
||||||
|
boolean retVal = false;
|
||||||
|
|
||||||
|
if(id instanceof UserStatusID)
|
||||||
|
{
|
||||||
|
UserStatusID userStatusId = (UserStatusID)id;
|
||||||
|
|
||||||
|
retVal = (mStatus == userStatusId.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JacksonXmlProperty(isAttribute = true, localName = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance")
|
||||||
|
@Override
|
||||||
|
public AliasIDType getType()
|
||||||
|
{
|
||||||
|
return AliasIDType.STATUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,12 +24,15 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
|||||||
import io.github.dsheirer.alias.id.AliasID;
|
import io.github.dsheirer.alias.id.AliasID;
|
||||||
import io.github.dsheirer.alias.id.AliasIDType;
|
import io.github.dsheirer.alias.id.AliasIDType;
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
import io.github.dsheirer.protocol.Protocol;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Integer talkgroup identifier with protocol.
|
* Integer talkgroup identifier with protocol.
|
||||||
*/
|
*/
|
||||||
public class Talkgroup extends AliasID
|
public class Talkgroup extends AliasID implements Comparable<Talkgroup>
|
||||||
{
|
{
|
||||||
|
private static final Logger mLog = LoggerFactory.getLogger(Talkgroup.class);
|
||||||
private Protocol mProtocol = Protocol.UNKNOWN;
|
private Protocol mProtocol = Protocol.UNKNOWN;
|
||||||
private int mValue;
|
private int mValue;
|
||||||
|
|
||||||
@@ -44,6 +47,12 @@ public class Talkgroup extends AliasID
|
|||||||
mValue = value;
|
mValue = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "value")
|
@JacksonXmlProperty(isAttribute = true, localName = "value")
|
||||||
public int getValue()
|
public int getValue()
|
||||||
{
|
{
|
||||||
@@ -53,6 +62,7 @@ public class Talkgroup extends AliasID
|
|||||||
public void setValue(int value)
|
public void setValue(int value)
|
||||||
{
|
{
|
||||||
mValue = value;
|
mValue = value;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
||||||
@@ -64,6 +74,7 @@ public class Talkgroup extends AliasID
|
|||||||
public void setProtocol(Protocol protocol)
|
public void setProtocol(Protocol protocol)
|
||||||
{
|
{
|
||||||
mProtocol = protocol;
|
mProtocol = protocol;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,7 +93,18 @@ public class Talkgroup extends AliasID
|
|||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
|
|
||||||
sb.append("Talkgroup:").append(TalkgroupFormatter.format(mProtocol, mValue));
|
String talkgroup = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
talkgroup = TalkgroupFormatter.format(mProtocol, mValue);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
mLog.error("Error formatting Talkgroup Protocol [" + mProtocol + "] value [" + mValue + "]", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
sb.append("Talkgroup:").append(talkgroup != null ? talkgroup : "error");
|
||||||
sb.append(" Protocol:").append((mProtocol));
|
sb.append(" Protocol:").append((mProtocol));
|
||||||
|
|
||||||
if(!isValid())
|
if(!isValid())
|
||||||
@@ -111,4 +133,22 @@ public class Talkgroup extends AliasID
|
|||||||
{
|
{
|
||||||
return AliasIDType.TALKGROUP;
|
return AliasIDType.TALKGROUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(Talkgroup other)
|
||||||
|
{
|
||||||
|
if(other == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getProtocol().equals(other.getProtocol()))
|
||||||
|
{
|
||||||
|
return Integer.compare(getValue(), other.getValue());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return getProtocol().compareTo(other.getProtocol());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,233 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.talkgroup;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JFormattedTextField;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.text.ParseException;
|
|
||||||
|
|
||||||
public class TalkgroupEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(TalkgroupEditor.class);
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String VALID_CHARACTERS_FOR_ASTERISK_MASKS = "0123456789 ";
|
|
||||||
private MaskFormatter mMaskFormatter = new MaskFormatter();
|
|
||||||
private JComboBox<Protocol> mComboProtocol;
|
|
||||||
private JFormattedTextField mTalkgroupField;
|
|
||||||
|
|
||||||
|
|
||||||
public TalkgroupEditor(AliasID aliasID)
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
setItem(aliasID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[right][left]", "[][]"));
|
|
||||||
|
|
||||||
add(new JLabel("Protocol:"));
|
|
||||||
|
|
||||||
mComboProtocol = new JComboBox<>();
|
|
||||||
|
|
||||||
DefaultComboBoxModel<Protocol> model = new DefaultComboBoxModel<>();
|
|
||||||
|
|
||||||
for(Protocol protocol : Protocol.TALKGROUP_PROTOCOLS)
|
|
||||||
{
|
|
||||||
model.addElement(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
mComboProtocol.setModel(model);
|
|
||||||
mComboProtocol.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
Protocol protocol = (Protocol)mComboProtocol.getSelectedItem();
|
|
||||||
updateEditor(protocol);
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mComboProtocol);
|
|
||||||
|
|
||||||
add(new JLabel("Value:"));
|
|
||||||
|
|
||||||
mTalkgroupField = new JFormattedTextField(mMaskFormatter);
|
|
||||||
mTalkgroupField.getDocument().addDocumentListener(this);
|
|
||||||
add(mTalkgroupField, "growx,push");
|
|
||||||
|
|
||||||
JLabel help = new JLabel("Help ...");
|
|
||||||
help.setForeground(Color.BLUE.brighter());
|
|
||||||
help.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
||||||
help.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
TalkgroupFormat talkgroupFormat = TalkgroupFormat.get(getCurrentProtocol());
|
|
||||||
JOptionPane.showMessageDialog(TalkgroupEditor.this,
|
|
||||||
talkgroupFormat.getValidRangeHelpText(), "Help", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(help, "align left");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateEditor(Protocol protocol)
|
|
||||||
{
|
|
||||||
TalkgroupFormat mask = TalkgroupFormat.get(protocol);
|
|
||||||
int currentValue = 0;
|
|
||||||
Talkgroup talkgroup = getTalkgroup();
|
|
||||||
|
|
||||||
if(talkgroup != null)
|
|
||||||
{
|
|
||||||
currentValue = talkgroup.getValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mTalkgroupField.setValue(null);
|
|
||||||
mTalkgroupField.setToolTipText(mask.getValidRangeHelpText());
|
|
||||||
mMaskFormatter.setMask(mask.getMask());
|
|
||||||
if(mask.getMask().contains("*"))
|
|
||||||
{
|
|
||||||
mMaskFormatter.setValidCharacters(VALID_CHARACTERS_FOR_ASTERISK_MASKS);
|
|
||||||
}
|
|
||||||
mTalkgroupField.setValue(TalkgroupFormatter.format(protocol, currentValue));
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
mLog.error("Error applying talkgroup editor mask to mask formatter [" + mask.getMask() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Protocol getCurrentProtocol()
|
|
||||||
{
|
|
||||||
return mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Current talkgroup alias id
|
|
||||||
*/
|
|
||||||
public Talkgroup getTalkgroup()
|
|
||||||
{
|
|
||||||
if(getItem() instanceof Talkgroup)
|
|
||||||
{
|
|
||||||
return (Talkgroup)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(AliasID aliasID)
|
|
||||||
{
|
|
||||||
super.setItem(aliasID);
|
|
||||||
|
|
||||||
Talkgroup talkgroup = getTalkgroup();
|
|
||||||
|
|
||||||
if(talkgroup != null)
|
|
||||||
{
|
|
||||||
Protocol currentProtocol = getCurrentProtocol();
|
|
||||||
if(currentProtocol == talkgroup.getProtocol())
|
|
||||||
{
|
|
||||||
updateEditor(talkgroup.getProtocol());
|
|
||||||
}
|
|
||||||
mComboProtocol.getModel().setSelectedItem(talkgroup.getProtocol());
|
|
||||||
|
|
||||||
String formatted = TalkgroupFormatter.format(talkgroup.getProtocol(), talkgroup.getValue());
|
|
||||||
mTalkgroupField.setValue(formatted);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mComboProtocol.getModel().setSelectedItem(Protocol.UNKNOWN);
|
|
||||||
mTalkgroupField.setValue(TalkgroupFormatter.format(getCurrentProtocol(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
Talkgroup talkgroup = getTalkgroup();
|
|
||||||
|
|
||||||
if(talkgroup != null)
|
|
||||||
{
|
|
||||||
Protocol protocol = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
|
|
||||||
if(protocol == null)
|
|
||||||
{
|
|
||||||
protocol = Protocol.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
int value = -1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
value = TalkgroupFormatter.parse(protocol, mTalkgroupField.getText());
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
//ignore ... value is still -1 and outside valid value range
|
|
||||||
}
|
|
||||||
|
|
||||||
TalkgroupFormat mask = TalkgroupFormat.get(protocol);
|
|
||||||
|
|
||||||
//Check for valid value within range ... notify user but allow value to persist
|
|
||||||
if(value < mask.getMinimumValidValue() || value > mask.getMaximumValidValue())
|
|
||||||
{
|
|
||||||
String message = "Invalid value [" + mTalkgroupField.getText() + "]. " + protocol.name() +
|
|
||||||
" valid range is [" + mask.getValidRangeDescription() + "]";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(TalkgroupEditor.this, message, "Invalid Talkgroup Value",
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
talkgroup.setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
talkgroup.setProtocol(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -36,9 +36,9 @@ public enum TalkgroupFormat
|
|||||||
{
|
{
|
||||||
APCO25("********", 0, 0xFFFFFF, "0 to 65,535",
|
APCO25("********", 0, 0xFFFFFF, "0 to 65,535",
|
||||||
"<html>APCO25 talkgroup valid range is 0 to 65,535"),
|
"<html>APCO25 talkgroup valid range is 0 to 65,535"),
|
||||||
FLEETSYNC("###-####", 1, 0x7FFFFF, "001-0001 to 127-8192",
|
FLEETSYNC("###-####", 0, 0x7FFFFF, "001-0001 to 127-8192",
|
||||||
"<html>Fleetsync valid ranges are 1-127(prefix)<br>and 1-8192(ident) (ie. 001-0001 to 127-8192)"),
|
"<html>Fleetsync valid ranges are 1-127(prefix)<br>and 1-8192(ident) (ie. 001-0001 to 127-8192)"),
|
||||||
LTR("##-###", 257, 5375, "01-001 to 20-255",
|
LTR("##-###", 0x101, 0x3FFF, "01-001 to 20-255",
|
||||||
"<html>LTR valid ranges are 1-20(repeater) and 1-255(talkgroup) (ie. 01-001 to 20-255)"),
|
"<html>LTR valid ranges are 1-20(repeater) and 1-255(talkgroup) (ie. 01-001 to 20-255)"),
|
||||||
MDC1200("*****", 1, 0xFFFF, "1 to 65,535",
|
MDC1200("*****", 1, 0xFFFF, "1 to 65,535",
|
||||||
"MDC-1200 valid value range is 1-65,535"),
|
"MDC-1200 valid value range is 1-65,535"),
|
||||||
@@ -124,7 +124,6 @@ public enum TalkgroupFormat
|
|||||||
return FLEETSYNC;
|
return FLEETSYNC;
|
||||||
case LTR:
|
case LTR:
|
||||||
case LTR_NET:
|
case LTR_NET:
|
||||||
case LTR_STANDARD:
|
|
||||||
return LTR;
|
return LTR;
|
||||||
case MDC1200:
|
case MDC1200:
|
||||||
return MDC1200;
|
return MDC1200;
|
||||||
|
|||||||
@@ -20,13 +20,15 @@
|
|||||||
|
|
||||||
package io.github.dsheirer.alias.id.talkgroup;
|
package io.github.dsheirer.alias.id.talkgroup;
|
||||||
|
|
||||||
|
import io.github.dsheirer.preference.identifier.IntegerFormat;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.APCO25TalkgroupFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.APCO25TalkgroupFormatter;
|
||||||
|
import io.github.dsheirer.preference.identifier.talkgroup.AbstractIntegerFormatter;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.FleetsyncTalkgroupFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.FleetsyncTalkgroupFormatter;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.IntegerFormatter;
|
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.LTRTalkgroupFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.LTRTalkgroupFormatter;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.MDC1200TalkgroupFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.MDC1200TalkgroupFormatter;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.MPT1327TalkgroupFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.MPT1327TalkgroupFormatter;
|
||||||
import io.github.dsheirer.preference.identifier.talkgroup.PassportTalkgroupFormatter;
|
import io.github.dsheirer.preference.identifier.talkgroup.PassportTalkgroupFormatter;
|
||||||
|
import io.github.dsheirer.preference.identifier.talkgroup.UnknownTalkgroupFormatter;
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
import io.github.dsheirer.protocol.Protocol;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -42,7 +44,7 @@ import java.util.Map;
|
|||||||
public class TalkgroupFormatter
|
public class TalkgroupFormatter
|
||||||
{
|
{
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(TalkgroupFormatter.class);
|
private final static Logger mLog = LoggerFactory.getLogger(TalkgroupFormatter.class);
|
||||||
private static Map<Protocol,IntegerFormatter> mFormatterMap = new EnumMap<>(Protocol.class);
|
private static Map<Protocol,AbstractIntegerFormatter> mFormatterMap = new EnumMap<>(Protocol.class);
|
||||||
|
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
@@ -51,11 +53,10 @@ public class TalkgroupFormatter
|
|||||||
LTRTalkgroupFormatter ltr = new LTRTalkgroupFormatter();
|
LTRTalkgroupFormatter ltr = new LTRTalkgroupFormatter();
|
||||||
mFormatterMap.put(Protocol.LTR, ltr);
|
mFormatterMap.put(Protocol.LTR, ltr);
|
||||||
mFormatterMap.put(Protocol.LTR_NET, ltr);
|
mFormatterMap.put(Protocol.LTR_NET, ltr);
|
||||||
mFormatterMap.put(Protocol.LTR_STANDARD, ltr);
|
|
||||||
mFormatterMap.put(Protocol.MDC1200, new MDC1200TalkgroupFormatter());
|
mFormatterMap.put(Protocol.MDC1200, new MDC1200TalkgroupFormatter());
|
||||||
mFormatterMap.put(Protocol.MPT1327, new MPT1327TalkgroupFormatter());
|
mFormatterMap.put(Protocol.MPT1327, new MPT1327TalkgroupFormatter());
|
||||||
mFormatterMap.put(Protocol.PASSPORT, new PassportTalkgroupFormatter());
|
mFormatterMap.put(Protocol.PASSPORT, new PassportTalkgroupFormatter());
|
||||||
mFormatterMap.put(Protocol.UNKNOWN, new IntegerFormatter());
|
mFormatterMap.put(Protocol.UNKNOWN, new UnknownTalkgroupFormatter());
|
||||||
}
|
}
|
||||||
|
|
||||||
public TalkgroupFormatter()
|
public TalkgroupFormatter()
|
||||||
@@ -67,7 +68,7 @@ public class TalkgroupFormatter
|
|||||||
*/
|
*/
|
||||||
public static int parse(Protocol protocol, String value) throws ParseException
|
public static int parse(Protocol protocol, String value) throws ParseException
|
||||||
{
|
{
|
||||||
IntegerFormatter formatter = mFormatterMap.get(protocol);
|
AbstractIntegerFormatter formatter = mFormatterMap.get(protocol);
|
||||||
|
|
||||||
if(formatter == null)
|
if(formatter == null)
|
||||||
{
|
{
|
||||||
@@ -82,7 +83,7 @@ public class TalkgroupFormatter
|
|||||||
*/
|
*/
|
||||||
public static String format(Protocol protocol, int value)
|
public static String format(Protocol protocol, int value)
|
||||||
{
|
{
|
||||||
IntegerFormatter formatter = mFormatterMap.get(protocol);
|
AbstractIntegerFormatter formatter = mFormatterMap.get(protocol);
|
||||||
|
|
||||||
if(formatter == null)
|
if(formatter == null)
|
||||||
{
|
{
|
||||||
@@ -91,4 +92,19 @@ public class TalkgroupFormatter
|
|||||||
|
|
||||||
return formatter.format(value);
|
return formatter.format(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the integer value to the specified integer format using the protocol specific formatter
|
||||||
|
*/
|
||||||
|
public static String format(Protocol protocol, int value, IntegerFormat format)
|
||||||
|
{
|
||||||
|
AbstractIntegerFormatter formatter = mFormatterMap.get(protocol);
|
||||||
|
|
||||||
|
if(formatter == null)
|
||||||
|
{
|
||||||
|
formatter = mFormatterMap.get(Protocol.UNKNOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formatter.format(value, format);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import io.github.dsheirer.protocol.Protocol;
|
|||||||
/**
|
/**
|
||||||
* Integer talkgroup identifier range of values with protocol.
|
* Integer talkgroup identifier range of values with protocol.
|
||||||
*/
|
*/
|
||||||
public class TalkgroupRange extends AliasID
|
public class TalkgroupRange extends AliasID implements Comparable<TalkgroupRange>
|
||||||
{
|
{
|
||||||
private Protocol mProtocol = Protocol.UNKNOWN;
|
private Protocol mProtocol = Protocol.UNKNOWN;
|
||||||
private int mMinTalkgroup;
|
private int mMinTalkgroup;
|
||||||
@@ -52,6 +52,12 @@ public class TalkgroupRange extends AliasID
|
|||||||
mMaxTalkgroup = maxTalkgroup;
|
mMaxTalkgroup = maxTalkgroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "min")
|
@JacksonXmlProperty(isAttribute = true, localName = "min")
|
||||||
public int getMinTalkgroup()
|
public int getMinTalkgroup()
|
||||||
{
|
{
|
||||||
@@ -61,6 +67,7 @@ public class TalkgroupRange extends AliasID
|
|||||||
public void setMinTalkgroup(int minTalkgroup)
|
public void setMinTalkgroup(int minTalkgroup)
|
||||||
{
|
{
|
||||||
mMinTalkgroup = minTalkgroup;
|
mMinTalkgroup = minTalkgroup;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "max")
|
@JacksonXmlProperty(isAttribute = true, localName = "max")
|
||||||
@@ -72,6 +79,7 @@ public class TalkgroupRange extends AliasID
|
|||||||
public void setMaxTalkgroup(int maxTalkgroup)
|
public void setMaxTalkgroup(int maxTalkgroup)
|
||||||
{
|
{
|
||||||
mMaxTalkgroup = maxTalkgroup;
|
mMaxTalkgroup = maxTalkgroup;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
@JacksonXmlProperty(isAttribute = true, localName = "protocol")
|
||||||
@@ -83,6 +91,7 @@ public class TalkgroupRange extends AliasID
|
|||||||
public void setProtocol(Protocol protocol)
|
public void setProtocol(Protocol protocol)
|
||||||
{
|
{
|
||||||
mProtocol = protocol;
|
mProtocol = protocol;
|
||||||
|
updateValueProperty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -97,7 +106,8 @@ public class TalkgroupRange extends AliasID
|
|||||||
return talkgroupFormat.getMinimumValidValue() <= mMinTalkgroup &&
|
return talkgroupFormat.getMinimumValidValue() <= mMinTalkgroup &&
|
||||||
mMinTalkgroup <= talkgroupFormat.getMaximumValidValue() &&
|
mMinTalkgroup <= talkgroupFormat.getMaximumValidValue() &&
|
||||||
talkgroupFormat.getMinimumValidValue() <= mMaxTalkgroup &&
|
talkgroupFormat.getMinimumValidValue() <= mMaxTalkgroup &&
|
||||||
mMaxTalkgroup <= talkgroupFormat.getMaximumValidValue();
|
mMaxTalkgroup <= talkgroupFormat.getMaximumValidValue() &&
|
||||||
|
mMinTalkgroup < mMaxTalkgroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
@@ -140,6 +150,12 @@ public class TalkgroupRange extends AliasID
|
|||||||
return getMinTalkgroup() <= talkgroupValue && talkgroupValue <= getMaxTalkgroup();
|
return getMinTalkgroup() <= talkgroupValue && talkgroupValue <= getMaxTalkgroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean overlaps(AliasID other)
|
||||||
|
{
|
||||||
|
return other instanceof TalkgroupRange && overlaps((TalkgroupRange)other);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates if this talkgroup range overlaps the talkgroup range argument.
|
* Indicates if this talkgroup range overlaps the talkgroup range argument.
|
||||||
* @param talkgroupRange to check for overlap
|
* @param talkgroupRange to check for overlap
|
||||||
@@ -161,4 +177,29 @@ public class TalkgroupRange extends AliasID
|
|||||||
{
|
{
|
||||||
return AliasIDType.TALKGROUP_RANGE;
|
return AliasIDType.TALKGROUP_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(TalkgroupRange other)
|
||||||
|
{
|
||||||
|
if(other == null)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getProtocol().equals(other.getProtocol()))
|
||||||
|
{
|
||||||
|
if(getMinTalkgroup() == other.getMinTalkgroup())
|
||||||
|
{
|
||||||
|
return Integer.compare(getMaxTalkgroup(), other.getMaxTalkgroup());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Integer.compare(getMinTalkgroup(), other.getMinTalkgroup());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return getProtocol().compareTo(other.getProtocol());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,271 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.alias.id.talkgroup;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.id.AliasID;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import io.github.dsheirer.protocol.Protocol;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.DefaultComboBoxModel;
|
|
||||||
import javax.swing.JComboBox;
|
|
||||||
import javax.swing.JFormattedTextField;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.text.MaskFormatter;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Cursor;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.text.ParseException;
|
|
||||||
|
|
||||||
public class TalkgroupRangeEditor extends DocumentListenerEditor<AliasID>
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(TalkgroupRangeEditor.class);
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String VALID_CHARACTERS_FOR_ASTERISK_MASKS = "0123456789 ";
|
|
||||||
private MaskFormatter mMaskFormatter = new MaskFormatter();
|
|
||||||
private JComboBox<Protocol> mComboProtocol;
|
|
||||||
private JFormattedTextField mMinTalkgroupField;
|
|
||||||
private JFormattedTextField mMaxTalkgroupField;
|
|
||||||
|
|
||||||
public TalkgroupRangeEditor(AliasID aliasID)
|
|
||||||
{
|
|
||||||
initGUI();
|
|
||||||
|
|
||||||
setItem(aliasID);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initGUI()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[right][left]", "[][]"));
|
|
||||||
|
|
||||||
add(new JLabel("Protocol:"));
|
|
||||||
|
|
||||||
mComboProtocol = new JComboBox<Protocol>();
|
|
||||||
|
|
||||||
DefaultComboBoxModel<Protocol> model = new DefaultComboBoxModel<>();
|
|
||||||
|
|
||||||
for(Protocol protocol : Protocol.TALKGROUP_PROTOCOLS)
|
|
||||||
{
|
|
||||||
model.addElement(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
mComboProtocol.setModel(model);
|
|
||||||
mComboProtocol.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
Protocol protocol = (Protocol)mComboProtocol.getSelectedItem();
|
|
||||||
updateEditor(protocol);
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(mComboProtocol);
|
|
||||||
|
|
||||||
add(new JLabel("Min:"));
|
|
||||||
|
|
||||||
mMinTalkgroupField = new JFormattedTextField(mMaskFormatter);
|
|
||||||
mMinTalkgroupField.getDocument().addDocumentListener(this);
|
|
||||||
add(mMinTalkgroupField, "growx,push");
|
|
||||||
|
|
||||||
add(new JLabel("Max:"));
|
|
||||||
|
|
||||||
mMaxTalkgroupField = new JFormattedTextField(mMaskFormatter);
|
|
||||||
mMaxTalkgroupField.getDocument().addDocumentListener(this);
|
|
||||||
add(mMaxTalkgroupField, "growx,push");
|
|
||||||
|
|
||||||
JLabel help = new JLabel("Help ...");
|
|
||||||
help.setForeground(Color.BLUE.brighter());
|
|
||||||
help.setCursor(new Cursor(Cursor.HAND_CURSOR));
|
|
||||||
help.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
TalkgroupFormat talkgroupFormat = TalkgroupFormat.get(getCurrentProtocol());
|
|
||||||
JOptionPane.showMessageDialog(TalkgroupRangeEditor.this,
|
|
||||||
talkgroupFormat.getValidRangeHelpText(), "Help", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(help, "align left");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateEditor(Protocol protocol)
|
|
||||||
{
|
|
||||||
TalkgroupFormat mask = TalkgroupFormat.get(protocol);
|
|
||||||
int currentMinValue = 0;
|
|
||||||
int currentMaxValue = 0;
|
|
||||||
TalkgroupRange talkgroupRange = getTalkgroupRange();
|
|
||||||
|
|
||||||
if(talkgroupRange != null)
|
|
||||||
{
|
|
||||||
currentMinValue = talkgroupRange.getMinTalkgroup();
|
|
||||||
currentMaxValue = talkgroupRange.getMaxTalkgroup();
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mMinTalkgroupField.setValue(null);
|
|
||||||
mMaxTalkgroupField.setValue(null);
|
|
||||||
|
|
||||||
mMinTalkgroupField.setToolTipText(mask.getValidRangeHelpText());
|
|
||||||
mMaxTalkgroupField.setToolTipText(mask.getValidRangeHelpText());
|
|
||||||
mMaskFormatter.setMask(mask.getMask());
|
|
||||||
if(mask.getMask().contains("*"))
|
|
||||||
{
|
|
||||||
mMaskFormatter.setValidCharacters(VALID_CHARACTERS_FOR_ASTERISK_MASKS);
|
|
||||||
}
|
|
||||||
|
|
||||||
mMinTalkgroupField.setValue(TalkgroupFormatter.format(protocol, currentMinValue));
|
|
||||||
mMaxTalkgroupField.setValue(TalkgroupFormatter.format(protocol, currentMaxValue));
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
mLog.error("Error applying talkgroup editor mask to mask formatter [" + mask.getMask() + "]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Protocol getCurrentProtocol()
|
|
||||||
{
|
|
||||||
return mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public TalkgroupRange getTalkgroupRange()
|
|
||||||
{
|
|
||||||
if(getItem() instanceof TalkgroupRange)
|
|
||||||
{
|
|
||||||
return (TalkgroupRange)getItem();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(AliasID aliasID)
|
|
||||||
{
|
|
||||||
super.setItem(aliasID);
|
|
||||||
|
|
||||||
TalkgroupRange talkgroupRange = getTalkgroupRange();
|
|
||||||
|
|
||||||
updateEditor(talkgroupRange.getProtocol());
|
|
||||||
|
|
||||||
if(talkgroupRange != null)
|
|
||||||
{
|
|
||||||
mComboProtocol.getModel().setSelectedItem(talkgroupRange.getProtocol());
|
|
||||||
String minFormatted = TalkgroupFormatter.format(talkgroupRange.getProtocol(), talkgroupRange.getMinTalkgroup());
|
|
||||||
mMinTalkgroupField.setValue(minFormatted);
|
|
||||||
String maxFormatted = TalkgroupFormatter.format(talkgroupRange.getProtocol(), talkgroupRange.getMaxTalkgroup());
|
|
||||||
mMaxTalkgroupField.setValue(maxFormatted);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mComboProtocol.getModel().setSelectedItem(Protocol.UNKNOWN);
|
|
||||||
mMinTalkgroupField.setValue(TalkgroupFormatter.format(getCurrentProtocol(), 0));
|
|
||||||
mMaxTalkgroupField.setValue(TalkgroupFormatter.format(getCurrentProtocol(), 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
TalkgroupRange talkgroupRange = getTalkgroupRange();
|
|
||||||
|
|
||||||
if(talkgroupRange != null)
|
|
||||||
{
|
|
||||||
Protocol protocol = mComboProtocol.getItemAt(mComboProtocol.getSelectedIndex());
|
|
||||||
|
|
||||||
if(protocol == null)
|
|
||||||
{
|
|
||||||
protocol = Protocol.UNKNOWN;
|
|
||||||
}
|
|
||||||
|
|
||||||
talkgroupRange.setProtocol(protocol);
|
|
||||||
|
|
||||||
int minValue = -1;
|
|
||||||
int maxValue = -1;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
minValue = TalkgroupFormatter.parse(protocol, mMinTalkgroupField.getText());
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
//ignore ... value is still -1 and outside valid value range
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
maxValue = TalkgroupFormatter.parse(protocol, mMaxTalkgroupField.getText());
|
|
||||||
}
|
|
||||||
catch(ParseException pe)
|
|
||||||
{
|
|
||||||
//ignore ... value is still -1 and outside valid value range
|
|
||||||
}
|
|
||||||
|
|
||||||
TalkgroupFormat mask = TalkgroupFormat.get(protocol);
|
|
||||||
|
|
||||||
//Check for valid value within range ... notify user but allow value to persist
|
|
||||||
if(minValue < mask.getMinimumValidValue() || minValue > mask.getMaximumValidValue())
|
|
||||||
{
|
|
||||||
String message = "Invalid minimum value [" + mMinTalkgroupField.getText() + "]. " + protocol.name() +
|
|
||||||
" valid range is [" + mask.getValidRangeDescription() + "]";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(TalkgroupRangeEditor.this, message,
|
|
||||||
"Invalid Talkgroup Value", JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
talkgroupRange.setMinTalkgroup(minValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check for valid value within range ... notify user but allow value to persist
|
|
||||||
if(maxValue < mask.getMinimumValidValue() || maxValue > mask.getMaximumValidValue())
|
|
||||||
{
|
|
||||||
String message = "Invalid maximum value [" + mMaxTalkgroupField.getText() + "]. " + protocol.name() +
|
|
||||||
" valid range is [" + mask.getValidRangeDescription() + "]";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(TalkgroupRangeEditor.this, message,
|
|
||||||
"Invalid Talkgroup Value", JOptionPane.ERROR_MESSAGE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
talkgroupRange.setMaxTalkgroup(maxValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
talkgroupRange.setProtocol(protocol);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
150
src/main/java/io/github/dsheirer/alias/id/tone/TonesID.java
Normal file
150
src/main/java/io/github/dsheirer/alias/id/tone/TonesID.java
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
/*
|
||||||
|
* *****************************************************************************
|
||||||
|
* Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* ****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.dsheirer.alias.id.tone;
|
||||||
|
|
||||||
|
import io.github.dsheirer.alias.id.AliasID;
|
||||||
|
import io.github.dsheirer.alias.id.AliasIDType;
|
||||||
|
import io.github.dsheirer.identifier.tone.Tone;
|
||||||
|
import io.github.dsheirer.identifier.tone.ToneSequence;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tone sequence alias identifier. This is used for matching tone sequences produced by the AMBE audio CODEC. Some
|
||||||
|
* examples include DTMF dialed numbers, KNOX tones, 2-Tone, Tone-outs, etc.
|
||||||
|
*/
|
||||||
|
public class TonesID extends AliasID implements ListChangeListener<Tone>
|
||||||
|
{
|
||||||
|
private ToneSequence mToneSequence;
|
||||||
|
|
||||||
|
public TonesID()
|
||||||
|
{
|
||||||
|
setToneSequence(new ToneSequence());
|
||||||
|
//Empty serialization constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance with the specified tone sequence
|
||||||
|
*/
|
||||||
|
public TonesID(ToneSequence toneSequence)
|
||||||
|
{
|
||||||
|
setToneSequence(toneSequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AliasIDType getType()
|
||||||
|
{
|
||||||
|
return AliasIDType.TONES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of tones that define this identifier
|
||||||
|
*/
|
||||||
|
|
||||||
|
public ToneSequence getToneSequence()
|
||||||
|
{
|
||||||
|
return mToneSequence;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the tone sequence(s) for this ID
|
||||||
|
*/
|
||||||
|
public void setToneSequence(ToneSequence toneSequence)
|
||||||
|
{
|
||||||
|
if(mToneSequence != null)
|
||||||
|
{
|
||||||
|
mToneSequence.tonesProperty().removeListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
mToneSequence = toneSequence;
|
||||||
|
mToneSequence.tonesProperty().addListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates if the other id is a tones identifier and has the exact same sequence of tones. However, it does not
|
||||||
|
* compare each of the tone duration value.
|
||||||
|
* @param id to check for match
|
||||||
|
* @return true if the identifiers match
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean matches(AliasID id)
|
||||||
|
{
|
||||||
|
boolean match = true;
|
||||||
|
|
||||||
|
if(mToneSequence.getTones().isEmpty() || !(id instanceof TonesID))
|
||||||
|
{
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<Tone> otherTones = ((TonesID)id).getToneSequence().getTones();
|
||||||
|
List<Tone> thisTones = mToneSequence.getTones();
|
||||||
|
|
||||||
|
if(thisTones.size() == otherTones.size())
|
||||||
|
{
|
||||||
|
for(int x = 0; x < thisTones.size(); x++)
|
||||||
|
{
|
||||||
|
if(thisTones.get(x).getAmbeTone() != otherTones.get(x).getAmbeTone())
|
||||||
|
{
|
||||||
|
match = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid()
|
||||||
|
{
|
||||||
|
return getToneSequence() != null && getToneSequence().hasTones();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAudioIdentifier()
|
||||||
|
{
|
||||||
|
//This is not an audio identifier in the context that this method is used for.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
if(getToneSequence() != null)
|
||||||
|
{
|
||||||
|
return "Tones: " + getToneSequence().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Tones: (empty)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onChanged(Change<? extends Tone> c)
|
||||||
|
{
|
||||||
|
updateValueProperty();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -125,8 +125,15 @@ public abstract class AbstractAudioModule extends Module implements IAudioSegmen
|
|||||||
audioSegment.linkTo(previous);
|
audioSegment.linkTo(previous);
|
||||||
}
|
}
|
||||||
|
|
||||||
audioSegment.addAudio(audioBuffer);
|
try
|
||||||
mAudioSampleCount += audioBuffer.length;
|
{
|
||||||
|
audioSegment.addAudio(audioBuffer);
|
||||||
|
mAudioSampleCount += audioBuffer.length;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
closeAudioSegment();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ import io.github.dsheirer.audio.convert.ISilenceGenerator;
|
|||||||
import io.github.dsheirer.identifier.IdentifierCollection;
|
import io.github.dsheirer.identifier.IdentifierCollection;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.util.ThreadPool;
|
import io.github.dsheirer.util.ThreadPool;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import org.apache.commons.math3.util.FastMath;
|
import org.apache.commons.math3.util.FastMath;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -52,7 +54,7 @@ public abstract class AudioBroadcaster implements Listener<AudioRecording>
|
|||||||
private ISilenceGenerator mSilenceGenerator;
|
private ISilenceGenerator mSilenceGenerator;
|
||||||
|
|
||||||
private Listener<BroadcastEvent> mBroadcastEventListener;
|
private Listener<BroadcastEvent> mBroadcastEventListener;
|
||||||
private BroadcastState mBroadcastState = BroadcastState.READY;
|
private ObjectProperty<BroadcastState> mBroadcastState = new SimpleObjectProperty<>(BroadcastState.READY);
|
||||||
|
|
||||||
private int mStreamedAudioCount = 0;
|
private int mStreamedAudioCount = 0;
|
||||||
private int mAgedOffAudioCount = 0;
|
private int mAgedOffAudioCount = 0;
|
||||||
@@ -90,6 +92,18 @@ public abstract class AudioBroadcaster implements Listener<AudioRecording>
|
|||||||
mSilenceGenerator = BroadcastFactory.getSilenceGenerator(broadcastConfiguration.getBroadcastFormat());
|
mSilenceGenerator = BroadcastFactory.getSilenceGenerator(broadcastConfiguration.getBroadcastFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable broadcast state property
|
||||||
|
*/
|
||||||
|
public ObjectProperty<BroadcastState> broadcastStateProperty()
|
||||||
|
{
|
||||||
|
return mBroadcastState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast binary audio data frames or sequences.
|
* Broadcast binary audio data frames or sequences.
|
||||||
*/
|
*/
|
||||||
@@ -251,18 +265,18 @@ public abstract class AudioBroadcaster implements Listener<AudioRecording>
|
|||||||
*/
|
*/
|
||||||
protected void setBroadcastState(BroadcastState state)
|
protected void setBroadcastState(BroadcastState state)
|
||||||
{
|
{
|
||||||
if(mBroadcastState != state)
|
if(mBroadcastState.get() != state)
|
||||||
{
|
{
|
||||||
if(state == BroadcastState.CONNECTED || state == BroadcastState.DISCONNECTED)
|
if(state == BroadcastState.CONNECTED || state == BroadcastState.DISCONNECTED)
|
||||||
{
|
{
|
||||||
mLog.info("[" + getStreamName() + "] status: " + state);
|
mLog.info("[" + getStreamName() + "] status: " + state);
|
||||||
}
|
}
|
||||||
|
|
||||||
mBroadcastState = state;
|
mBroadcastState.setValue(state);
|
||||||
|
|
||||||
broadcast(new BroadcastEvent(this, BroadcastEvent.Event.BROADCASTER_STATE_CHANGE));
|
broadcast(new BroadcastEvent(this, BroadcastEvent.Event.BROADCASTER_STATE_CHANGE));
|
||||||
|
|
||||||
if(mBroadcastState.isErrorState())
|
if(mBroadcastState.get().isErrorState())
|
||||||
{
|
{
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
@@ -291,7 +305,7 @@ public abstract class AudioBroadcaster implements Listener<AudioRecording>
|
|||||||
*/
|
*/
|
||||||
public BroadcastState getBroadcastState()
|
public BroadcastState getBroadcastState()
|
||||||
{
|
{
|
||||||
return mBroadcastState;
|
return mBroadcastState.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
/*******************************************************************************
|
/*
|
||||||
* sdrtrunk
|
|
||||||
* 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
*/
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast;
|
package io.github.dsheirer.audio.broadcast;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
@@ -26,6 +29,17 @@ import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
|
|||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
|
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration;
|
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration;
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2Configuration;
|
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2Configuration;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.binding.Bindings;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.IntegerProperty;
|
||||||
|
import javafx.beans.property.LongProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleLongProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.SocketAddress;
|
import java.net.SocketAddress;
|
||||||
@@ -39,18 +53,32 @@ import java.net.SocketAddress;
|
|||||||
@JacksonXmlRootElement(localName = "stream")
|
@JacksonXmlRootElement(localName = "stream")
|
||||||
public abstract class BroadcastConfiguration
|
public abstract class BroadcastConfiguration
|
||||||
{
|
{
|
||||||
|
// Static unique channel identifier tracking
|
||||||
|
private static int UNIQUE_ID = 0;
|
||||||
|
|
||||||
private BroadcastFormat mBroadcastFormat = BroadcastFormat.MP3;
|
private BroadcastFormat mBroadcastFormat = BroadcastFormat.MP3;
|
||||||
private String mName;
|
private StringProperty mName = new SimpleStringProperty();
|
||||||
private String mHost;
|
private StringProperty mHost = new SimpleStringProperty();
|
||||||
private int mPort;
|
private IntegerProperty mPort = new SimpleIntegerProperty(80);
|
||||||
private String mPassword;
|
private StringProperty mPassword = new SimpleStringProperty();
|
||||||
private long mDelay;
|
private LongProperty mDelay = new SimpleLongProperty();
|
||||||
private long mMaximumRecordingAge = 10 * 60 * 1000; //10 minutes default
|
private LongProperty mMaximumRecordingAge = new SimpleLongProperty(10 * 60 * 1000); //10 minutes default
|
||||||
private boolean mEnabled = true;
|
private BooleanProperty mEnabled = new SimpleBooleanProperty(false);
|
||||||
|
private BooleanProperty mValid;
|
||||||
|
private int mId = ++UNIQUE_ID;
|
||||||
|
|
||||||
public BroadcastConfiguration()
|
public BroadcastConfiguration()
|
||||||
{
|
{
|
||||||
//No-arg constructor required for JAXB
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique identifier for this configuration.
|
||||||
|
* Note: unique ids are generated at runtime and have no persistent context across sessions.
|
||||||
|
*/
|
||||||
|
@JsonIgnore
|
||||||
|
public int getId()
|
||||||
|
{
|
||||||
|
return mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,6 +94,76 @@ public abstract class BroadcastConfiguration
|
|||||||
mBroadcastFormat = format;
|
mBroadcastFormat = format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream name
|
||||||
|
*/
|
||||||
|
public StringProperty nameProperty()
|
||||||
|
{
|
||||||
|
return mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server host name
|
||||||
|
*/
|
||||||
|
public StringProperty hostProperty()
|
||||||
|
{
|
||||||
|
return mHost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed port
|
||||||
|
*/
|
||||||
|
public IntegerProperty portProperty()
|
||||||
|
{
|
||||||
|
return mPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feed password
|
||||||
|
*/
|
||||||
|
public StringProperty passwordProperty()
|
||||||
|
{
|
||||||
|
return mPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delay introduced for each recording before streaming
|
||||||
|
*/
|
||||||
|
public LongProperty delayProperty()
|
||||||
|
{
|
||||||
|
return mDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maximum allowable age of a recording to stream. Recordings that exceed this threshold will be aged off.
|
||||||
|
*/
|
||||||
|
public LongProperty maximumRecordingAgeProperty()
|
||||||
|
{
|
||||||
|
return mMaximumRecordingAge;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stream enabled property
|
||||||
|
*/
|
||||||
|
public BooleanProperty enabledProperty()
|
||||||
|
{
|
||||||
|
return mEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration valid property
|
||||||
|
*/
|
||||||
|
public BooleanProperty validProperty()
|
||||||
|
{
|
||||||
|
if(mValid == null)
|
||||||
|
{
|
||||||
|
mValid = new SimpleBooleanProperty();
|
||||||
|
mValid.bind(Bindings.and(Bindings.isNotNull(mHost), Bindings.greaterThan(mPort, 0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return mValid;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcast server type
|
* Broadcast server type
|
||||||
*/
|
*/
|
||||||
@@ -83,7 +181,7 @@ public abstract class BroadcastConfiguration
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "name")
|
@JacksonXmlProperty(isAttribute = true, localName = "name")
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return mName;
|
return mName.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,7 +191,7 @@ public abstract class BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public void setName(String name)
|
public void setName(String name)
|
||||||
{
|
{
|
||||||
mName = name;
|
mName.set(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -110,7 +208,7 @@ public abstract class BroadcastConfiguration
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "host")
|
@JacksonXmlProperty(isAttribute = true, localName = "host")
|
||||||
public String getHost()
|
public String getHost()
|
||||||
{
|
{
|
||||||
return mHost;
|
return mHost.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,7 +218,7 @@ public abstract class BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public void setHost(String host)
|
public void setHost(String host)
|
||||||
{
|
{
|
||||||
mHost = host;
|
mHost.set(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,7 +235,7 @@ public abstract class BroadcastConfiguration
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "port")
|
@JacksonXmlProperty(isAttribute = true, localName = "port")
|
||||||
public int getPort()
|
public int getPort()
|
||||||
{
|
{
|
||||||
return mPort;
|
return mPort.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,7 +245,7 @@ public abstract class BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public void setPort(int port)
|
public void setPort(int port)
|
||||||
{
|
{
|
||||||
mPort = port;
|
mPort.set(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -155,7 +253,7 @@ public abstract class BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public boolean hasPort()
|
public boolean hasPort()
|
||||||
{
|
{
|
||||||
return mPort > 0;
|
return mPort.get() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
@@ -170,7 +268,7 @@ public abstract class BroadcastConfiguration
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "password")
|
@JacksonXmlProperty(isAttribute = true, localName = "password")
|
||||||
public String getPassword()
|
public String getPassword()
|
||||||
{
|
{
|
||||||
return mPassword;
|
return mPassword.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,7 +278,7 @@ public abstract class BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public void setPassword(String password)
|
public void setPassword(String password)
|
||||||
{
|
{
|
||||||
mPassword = password;
|
mPassword.set(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -211,7 +309,7 @@ public abstract class BroadcastConfiguration
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "delay")
|
@JacksonXmlProperty(isAttribute = true, localName = "delay")
|
||||||
public long getDelay()
|
public long getDelay()
|
||||||
{
|
{
|
||||||
return mDelay;
|
return mDelay.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,7 +318,7 @@ public abstract class BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public void setDelay(long delay)
|
public void setDelay(long delay)
|
||||||
{
|
{
|
||||||
mDelay = delay;
|
mDelay.set(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -231,7 +329,7 @@ public abstract class BroadcastConfiguration
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "maximum_recording_age")
|
@JacksonXmlProperty(isAttribute = true, localName = "maximum_recording_age")
|
||||||
public long getMaximumRecordingAge()
|
public long getMaximumRecordingAge()
|
||||||
{
|
{
|
||||||
return mMaximumRecordingAge;
|
return mMaximumRecordingAge.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -241,7 +339,7 @@ public abstract class BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public void setMaximumRecordingAge(long age)
|
public void setMaximumRecordingAge(long age)
|
||||||
{
|
{
|
||||||
mMaximumRecordingAge = age;
|
mMaximumRecordingAge.set(age);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,12 +348,12 @@ public abstract class BroadcastConfiguration
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "enabled")
|
@JacksonXmlProperty(isAttribute = true, localName = "enabled")
|
||||||
public boolean isEnabled()
|
public boolean isEnabled()
|
||||||
{
|
{
|
||||||
return mEnabled;
|
return mEnabled.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setEnabled(boolean enabled)
|
public void setEnabled(boolean enabled)
|
||||||
{
|
{
|
||||||
mEnabled = enabled;
|
mEnabled.set(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -302,6 +400,15 @@ public abstract class BroadcastConfiguration
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isValid()
|
public boolean isValid()
|
||||||
{
|
{
|
||||||
return mHost != null && mPort > 0;
|
return validProperty().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
|
||||||
|
*/
|
||||||
|
public static Callback<BroadcastConfiguration, Observable[]> extractor()
|
||||||
|
{
|
||||||
|
return (BroadcastConfiguration b) -> new Observable[] {b.nameProperty(), b.hostProperty(), b.portProperty(),
|
||||||
|
b.passwordProperty(), b.maximumRecordingAgeProperty(), b.delayProperty(), b.enabledProperty()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,126 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* 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 <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.gui.editor.DocumentListenerEditor;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
public abstract class BroadcastConfigurationEditor extends DocumentListenerEditor<BroadcastConfiguration>
|
|
||||||
{
|
|
||||||
protected IconManager mIconManager;
|
|
||||||
protected BroadcastModel mBroadcastModel;
|
|
||||||
protected AliasModel mAliasModel;
|
|
||||||
|
|
||||||
public BroadcastConfigurationEditor(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
mBroadcastModel = broadcastModel;
|
|
||||||
mAliasModel = aliasModel;
|
|
||||||
mIconManager = iconManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the configuration with the new name and prompts the user to update any aliases that have a broadcast
|
|
||||||
* channel alias id with the old name to update to the new name.
|
|
||||||
*
|
|
||||||
* @param broadcastConfiguration to assign a new channel name
|
|
||||||
* @param newName to assign to the broadcast configuration. Note: assumes that validateConfiguration() has been
|
|
||||||
* invoked to verify that newName is non-null and non-empty
|
|
||||||
*/
|
|
||||||
protected void updateConfigurationName(BroadcastConfiguration broadcastConfiguration, String newName)
|
|
||||||
{
|
|
||||||
String previousName = broadcastConfiguration.getName();
|
|
||||||
|
|
||||||
if(previousName == null || previousName.isEmpty())
|
|
||||||
{
|
|
||||||
broadcastConfiguration.setName(newName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!previousName.equals(newName))
|
|
||||||
{
|
|
||||||
mAliasModel.renameBroadcastChannel(previousName, newName);
|
|
||||||
broadcastConfiguration.setName(newName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates a text field control for a non-null, non-empty value
|
|
||||||
* @param field to validate
|
|
||||||
* @param title to use for error dialog
|
|
||||||
* @param message to use for error dialog
|
|
||||||
* @return true if field contains a non-null, non-empty value
|
|
||||||
*/
|
|
||||||
protected boolean validateTextField(JTextField field, String title, String message)
|
|
||||||
{
|
|
||||||
String text = field.getText();
|
|
||||||
|
|
||||||
if(text == null || text.isEmpty())
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog(BroadcastConfigurationEditor.this, message, title,
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
field.requestFocus();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the text field control that contains an integer value for non-null, non-empty and within the
|
|
||||||
* specified min/max valid range.
|
|
||||||
* @param field to validate
|
|
||||||
* @param title to use for error dialog
|
|
||||||
* @param message to use for error dialog
|
|
||||||
* @param minValid value
|
|
||||||
* @param maxValid value
|
|
||||||
* @return true if field contains a non-null, non-empty value within the valid min/max range
|
|
||||||
*/
|
|
||||||
protected boolean validateIntegerTextField(JTextField field, String title, String message, int minValid, int maxValid)
|
|
||||||
{
|
|
||||||
if(validateTextField(field, title, message))
|
|
||||||
{
|
|
||||||
String text = field.getText();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int value = Integer.parseInt(text);
|
|
||||||
|
|
||||||
if(minValid <= value && value <= maxValid)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(BroadcastConfigurationEditor.this, message, title,
|
|
||||||
JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
field.requestFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -23,27 +23,18 @@ package io.github.dsheirer.audio.broadcast;
|
|||||||
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
import io.github.dsheirer.alias.AliasModel;
|
||||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyConfiguration;
|
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyConfiguration;
|
||||||
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastHTTPAudioBroadcaster;
|
import io.github.dsheirer.audio.broadcast.icecast.IcecastHTTPAudioBroadcaster;
|
||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastHTTPConfiguration;
|
import io.github.dsheirer.audio.broadcast.icecast.IcecastHTTPConfiguration;
|
||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastHTTPConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastTCPAudioBroadcaster;
|
import io.github.dsheirer.audio.broadcast.icecast.IcecastTCPAudioBroadcaster;
|
||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastTCPConfiguration;
|
import io.github.dsheirer.audio.broadcast.icecast.IcecastTCPConfiguration;
|
||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastTCPConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1AudioBroadcaster;
|
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1AudioBroadcaster;
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration;
|
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration;
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1ConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2AudioBroadcaster;
|
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2AudioBroadcaster;
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2Configuration;
|
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2Configuration;
|
||||||
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2ConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.convert.IAudioConverter;
|
import io.github.dsheirer.audio.convert.IAudioConverter;
|
||||||
import io.github.dsheirer.audio.convert.ISilenceGenerator;
|
import io.github.dsheirer.audio.convert.ISilenceGenerator;
|
||||||
import io.github.dsheirer.audio.convert.MP3AudioConverter;
|
import io.github.dsheirer.audio.convert.MP3AudioConverter;
|
||||||
import io.github.dsheirer.audio.convert.MP3SilenceGenerator;
|
import io.github.dsheirer.audio.convert.MP3SilenceGenerator;
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.gui.editor.EmptyEditor;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -140,48 +131,6 @@ public class BroadcastFactory
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an editor for the specified broadcastAudio configuration
|
|
||||||
*
|
|
||||||
* @param configuration to modify or view
|
|
||||||
* @param broadcastModel model for broadcastAudio configurations
|
|
||||||
* @return an editor for the specified broadcastAudio configuration
|
|
||||||
*/
|
|
||||||
public static Editor<BroadcastConfiguration> getEditor(UserPreferences userPreferences,
|
|
||||||
BroadcastConfiguration configuration,
|
|
||||||
BroadcastModel broadcastModel,
|
|
||||||
AliasModel aliasModel,
|
|
||||||
IconManager iconManager)
|
|
||||||
{
|
|
||||||
Editor<BroadcastConfiguration> editor;
|
|
||||||
|
|
||||||
switch(configuration.getBroadcastServerType())
|
|
||||||
{
|
|
||||||
case BROADCASTIFY:
|
|
||||||
editor = new BroadcastifyConfigurationEditor(userPreferences, broadcastModel, aliasModel, iconManager);
|
|
||||||
break;
|
|
||||||
case ICECAST_TCP:
|
|
||||||
editor = new IcecastTCPConfigurationEditor(broadcastModel, aliasModel, iconManager);
|
|
||||||
break;
|
|
||||||
case ICECAST_HTTP:
|
|
||||||
editor = new IcecastHTTPConfigurationEditor(broadcastModel, aliasModel, iconManager);
|
|
||||||
break;
|
|
||||||
case SHOUTCAST_V1:
|
|
||||||
editor = new ShoutcastV1ConfigurationEditor(broadcastModel, aliasModel, iconManager);
|
|
||||||
break;
|
|
||||||
case SHOUTCAST_V2:
|
|
||||||
editor = new ShoutcastV2ConfigurationEditor(broadcastModel, aliasModel, iconManager);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
editor = new EmptyEditor<BroadcastConfiguration>();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.setItem(configuration);
|
|
||||||
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ISilenceGenerator getSilenceGenerator(BroadcastFormat format)
|
public static ISilenceGenerator getSilenceGenerator(BroadcastFormat format)
|
||||||
{
|
{
|
||||||
switch(format)
|
switch(format)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* * ******************************************************************************
|
* * ******************************************************************************
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* *
|
* *
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
* * 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
|
* * it under the terms of the GNU General Public License as published by
|
||||||
@@ -29,6 +29,9 @@ import io.github.dsheirer.properties.SystemProperties;
|
|||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.util.ThreadPool;
|
import io.github.dsheirer.util.ThreadPool;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -68,11 +71,12 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
public static final String[] COLUMN_NAMES = new String[]
|
public static final String[] COLUMN_NAMES = new String[]
|
||||||
{"Streaming", "Name", "Status", "Queued", "Streamed", "Aged Off"};
|
{"Streaming", "Name", "Status", "Queued", "Streamed", "Aged Off"};
|
||||||
|
|
||||||
private List<BroadcastConfiguration> mBroadcastConfigurations = new CopyOnWriteArrayList<>();
|
private ObservableList<ConfiguredBroadcast> mConfiguredBroadcasts =
|
||||||
|
FXCollections.observableArrayList(ConfiguredBroadcast.extractor());
|
||||||
|
private ObservableList<BroadcastConfiguration> mBroadcastConfigurations =
|
||||||
|
FXCollections.observableArrayList(BroadcastConfiguration.extractor());
|
||||||
private List<AudioRecording> mRecordingQueue = new CopyOnWriteArrayList<>();
|
private List<AudioRecording> mRecordingQueue = new CopyOnWriteArrayList<>();
|
||||||
|
private Map<Integer,AudioBroadcaster> mBroadcasterMap = new HashMap<>();
|
||||||
private Map<String,BroadcastConfiguration> mBroadcastConfigurationMap = new HashMap<>();
|
|
||||||
private Map<String,AudioBroadcaster> mBroadcasterMap = new HashMap<>();
|
|
||||||
private IconManager mIconManager;
|
private IconManager mIconManager;
|
||||||
private AliasModel mAliasModel;
|
private AliasModel mAliasModel;
|
||||||
private Broadcaster<BroadcastEvent> mBroadcastEventBroadcaster = new Broadcaster<>();
|
private Broadcaster<BroadcastEvent> mBroadcastEventBroadcaster = new Broadcaster<>();
|
||||||
@@ -89,6 +93,31 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
ThreadPool.SCHEDULED.scheduleAtFixedRate(new RecordingDeletionMonitor(), 15l, 15l, TimeUnit.SECONDS);
|
ThreadPool.SCHEDULED.scheduleAtFixedRate(new RecordingDeletionMonitor(), 15l, 15l, TimeUnit.SECONDS);
|
||||||
|
|
||||||
removeOrphanedTemporaryRecordings();
|
removeOrphanedTemporaryRecordings();
|
||||||
|
mBroadcastConfigurations.addListener(new ConfigurationChangeListener());
|
||||||
|
|
||||||
|
//TODO: remove broadcast of change events and simply have the playlist manager register as a listener on the configs
|
||||||
|
//TODO: list to detect changes and execute playlist saves.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of broadcast configurations with (optional) audio broadcasters created from each configuration
|
||||||
|
*/
|
||||||
|
public ObservableList<ConfiguredBroadcast> getConfiguredBroadcasts()
|
||||||
|
{
|
||||||
|
return mConfiguredBroadcasts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all broadcast configurations and shuts down any running broadcasters.
|
||||||
|
*/
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
List<BroadcastConfiguration> configsToRemove = new ArrayList<>(mBroadcastConfigurations);
|
||||||
|
|
||||||
|
for(BroadcastConfiguration configToRemove: configsToRemove)
|
||||||
|
{
|
||||||
|
removeBroadcastConfiguration(configToRemove);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +138,7 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
/**
|
/**
|
||||||
* Current list of broadcastAudio configurations
|
* Current list of broadcastAudio configurations
|
||||||
*/
|
*/
|
||||||
public List<BroadcastConfiguration> getBroadcastConfigurations()
|
public ObservableList<BroadcastConfiguration> getBroadcastConfigurations()
|
||||||
{
|
{
|
||||||
return mBroadcastConfigurations;
|
return mBroadcastConfigurations;
|
||||||
}
|
}
|
||||||
@@ -128,7 +157,7 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
/**
|
/**
|
||||||
* Adds the broadcastAudio configuration to this model
|
* Adds the broadcastAudio configuration to this model
|
||||||
*/
|
*/
|
||||||
public void addBroadcastConfiguration(BroadcastConfiguration configuration)
|
public ConfiguredBroadcast addBroadcastConfiguration(BroadcastConfiguration configuration)
|
||||||
{
|
{
|
||||||
if(configuration != null)
|
if(configuration != null)
|
||||||
{
|
{
|
||||||
@@ -137,16 +166,20 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
if(!mBroadcastConfigurations.contains(configuration))
|
if(!mBroadcastConfigurations.contains(configuration))
|
||||||
{
|
{
|
||||||
mBroadcastConfigurations.add(configuration);
|
mBroadcastConfigurations.add(configuration);
|
||||||
|
ConfiguredBroadcast configuredBroadcast = new ConfiguredBroadcast(configuration);
|
||||||
|
mConfiguredBroadcasts.add(configuredBroadcast);
|
||||||
|
|
||||||
int index = mBroadcastConfigurations.size() - 1;
|
int index = mBroadcastConfigurations.size() - 1;
|
||||||
|
|
||||||
fireTableRowsInserted(index, index);
|
fireTableRowsInserted(index, index);
|
||||||
|
|
||||||
mBroadcastConfigurationMap.put(configuration.getName(), configuration);
|
|
||||||
|
|
||||||
process(new BroadcastEvent(configuration, BroadcastEvent.Event.CONFIGURATION_ADD));
|
process(new BroadcastEvent(configuration, BroadcastEvent.Event.CONFIGURATION_ADD));
|
||||||
|
|
||||||
|
return configuredBroadcast;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -259,7 +292,15 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
|
|
||||||
mBroadcastConfigurations.remove(broadcastConfiguration);
|
mBroadcastConfigurations.remove(broadcastConfiguration);
|
||||||
|
|
||||||
mBroadcastConfigurationMap.remove(broadcastConfiguration.getName());
|
Iterator<ConfiguredBroadcast> it = mConfiguredBroadcasts.iterator();
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
if(it.next().getBroadcastConfiguration() == broadcastConfiguration)
|
||||||
|
{
|
||||||
|
it.remove();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
process(new BroadcastEvent(broadcastConfiguration, BroadcastEvent.Event.CONFIGURATION_DELETE));
|
process(new BroadcastEvent(broadcastConfiguration, BroadcastEvent.Event.CONFIGURATION_DELETE));
|
||||||
|
|
||||||
@@ -305,16 +346,32 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
*/
|
*/
|
||||||
private void createBroadcaster(BroadcastConfiguration broadcastConfiguration)
|
private void createBroadcaster(BroadcastConfiguration broadcastConfiguration)
|
||||||
{
|
{
|
||||||
if(broadcastConfiguration != null && broadcastConfiguration.isEnabled() && broadcastConfiguration.isValid() &&
|
if(broadcastConfiguration != null && broadcastConfiguration.isEnabled() && broadcastConfiguration.isValid())
|
||||||
!mBroadcasterMap.containsKey(broadcastConfiguration.getName()))
|
|
||||||
{
|
{
|
||||||
|
//Remove current broadcaster if one exists
|
||||||
|
deleteBroadcaster(broadcastConfiguration.getId());
|
||||||
|
|
||||||
AudioBroadcaster audioBroadcaster = BroadcastFactory.getBroadcaster(broadcastConfiguration, mAliasModel);
|
AudioBroadcaster audioBroadcaster = BroadcastFactory.getBroadcaster(broadcastConfiguration, mAliasModel);
|
||||||
|
|
||||||
if(audioBroadcaster != null)
|
if(audioBroadcaster != null)
|
||||||
{
|
{
|
||||||
audioBroadcaster.setListener(broadcastEvent -> process(broadcastEvent));
|
audioBroadcaster.setListener(broadcastEvent -> process(broadcastEvent));
|
||||||
audioBroadcaster.start();
|
audioBroadcaster.start();
|
||||||
mBroadcasterMap.put(audioBroadcaster.getBroadcastConfiguration().getName(), audioBroadcaster);
|
|
||||||
|
Iterator<ConfiguredBroadcast> it = mConfiguredBroadcasts.iterator();
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
ConfiguredBroadcast configuredBroadcast = it.next();
|
||||||
|
|
||||||
|
if(configuredBroadcast.getBroadcastConfiguration() == broadcastConfiguration)
|
||||||
|
{
|
||||||
|
configuredBroadcast.setAudioBroadcaster(audioBroadcaster);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mBroadcasterMap.put(audioBroadcaster.getBroadcastConfiguration().getId(), audioBroadcaster);
|
||||||
|
|
||||||
int index = mBroadcastConfigurations.indexOf(audioBroadcaster.getBroadcastConfiguration());
|
int index = mBroadcastConfigurations.indexOf(audioBroadcaster.getBroadcastConfiguration());
|
||||||
|
|
||||||
if(index >= 0)
|
if(index >= 0)
|
||||||
@@ -330,16 +387,29 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
/**
|
/**
|
||||||
* Shut down a broadcaster created from the configuration and remove it from this model
|
* Shut down a broadcaster created from the configuration and remove it from this model
|
||||||
*/
|
*/
|
||||||
private void deleteBroadcaster(String name)
|
private void deleteBroadcaster(int id)
|
||||||
{
|
{
|
||||||
if(name != null && mBroadcasterMap.containsKey(name))
|
if(mBroadcasterMap.containsKey(id))
|
||||||
{
|
{
|
||||||
AudioBroadcaster audioBroadcaster = mBroadcasterMap.remove(name);
|
AudioBroadcaster audioBroadcaster = mBroadcasterMap.remove(id);
|
||||||
|
|
||||||
if(audioBroadcaster != null)
|
if(audioBroadcaster != null)
|
||||||
{
|
{
|
||||||
|
Iterator<ConfiguredBroadcast> it = mConfiguredBroadcasts.iterator();
|
||||||
|
while(it.hasNext())
|
||||||
|
{
|
||||||
|
ConfiguredBroadcast configuredBroadcast = it.next();
|
||||||
|
|
||||||
|
if(configuredBroadcast.getBroadcastConfiguration().getId() == id)
|
||||||
|
{
|
||||||
|
configuredBroadcast.setAudioBroadcaster(null);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
audioBroadcaster.stop();
|
audioBroadcaster.stop();
|
||||||
audioBroadcaster.removeListener();
|
audioBroadcaster.removeListener();
|
||||||
|
audioBroadcaster.dispose();
|
||||||
|
|
||||||
int index = mBroadcastConfigurations.indexOf(audioBroadcaster.getBroadcastConfiguration());
|
int index = mBroadcastConfigurations.indexOf(audioBroadcaster.getBroadcastConfiguration());
|
||||||
|
|
||||||
@@ -358,7 +428,15 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
*/
|
*/
|
||||||
public BroadcastConfiguration getBroadcastConfiguration(String streamName)
|
public BroadcastConfiguration getBroadcastConfiguration(String streamName)
|
||||||
{
|
{
|
||||||
return mBroadcastConfigurationMap.get(streamName);
|
for(BroadcastConfiguration config: mBroadcastConfigurations)
|
||||||
|
{
|
||||||
|
if(config.getName() != null && config.getName().contentEquals(streamName))
|
||||||
|
{
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -399,24 +477,23 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
break;
|
break;
|
||||||
case CONFIGURATION_CHANGE:
|
case CONFIGURATION_CHANGE:
|
||||||
BroadcastConfiguration broadcastConfiguration = broadcastEvent.getBroadcastConfiguration();
|
BroadcastConfiguration broadcastConfiguration = broadcastEvent.getBroadcastConfiguration();
|
||||||
int index = mBroadcastConfigurations.indexOf(broadcastConfiguration);
|
|
||||||
|
|
||||||
//Delete the existing broadcaster for any broadcast configuration changes
|
//Delete the broadcaster if it exists
|
||||||
String previousChannelName = cleanupMapAssociations(broadcastConfiguration);
|
deleteBroadcaster(broadcastConfiguration.getId());
|
||||||
deleteBroadcaster(previousChannelName);
|
|
||||||
|
|
||||||
//If the configuration is enabled, create a new broadcaster after a brief delay
|
//If the configuration is enabled, create a new broadcaster after a brief delay
|
||||||
if(broadcastConfiguration.isEnabled())
|
if(broadcastConfiguration.isEnabled())
|
||||||
{
|
{
|
||||||
//Delay restarting the broadcaster to allow remote server time to cleanup
|
//Delay restarting the broadcaster to allow remote server time to cleanup
|
||||||
ThreadPool.SCHEDULED.schedule(new DelayedBroadcasterStartup(broadcastConfiguration),
|
ThreadPool.SCHEDULED.schedule(new DelayedBroadcasterStartup(broadcastConfiguration),
|
||||||
3, TimeUnit.SECONDS);
|
1, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int index = mBroadcastConfigurations.indexOf(broadcastConfiguration);
|
||||||
fireTableRowsUpdated(index, index);
|
fireTableRowsUpdated(index, index);
|
||||||
break;
|
break;
|
||||||
case CONFIGURATION_DELETE:
|
case CONFIGURATION_DELETE:
|
||||||
deleteBroadcaster(broadcastEvent.getBroadcastConfiguration().getName());
|
deleteBroadcaster(broadcastEvent.getBroadcastConfiguration().getId());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -457,37 +534,6 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
broadcast(broadcastEvent);
|
broadcast(broadcastEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* When the name of a broadcast configuration changes, remove the old map associations so that they can be replaced
|
|
||||||
* with the new map associations. Remove any broadcaster that is associated with the old configuration name.
|
|
||||||
*
|
|
||||||
* @param broadcastConfiguration
|
|
||||||
* @return previous or current channel name that has been replaced with the current configuration channel name so
|
|
||||||
* that anything else associated with the previous name can be cleaned up.
|
|
||||||
*/
|
|
||||||
private String cleanupMapAssociations(BroadcastConfiguration broadcastConfiguration)
|
|
||||||
{
|
|
||||||
String oldName = null;
|
|
||||||
|
|
||||||
for(Map.Entry<String,BroadcastConfiguration> entry : mBroadcastConfigurationMap.entrySet())
|
|
||||||
{
|
|
||||||
if(entry.getValue() == broadcastConfiguration)
|
|
||||||
{
|
|
||||||
oldName = entry.getKey();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(oldName != null)
|
|
||||||
{
|
|
||||||
mBroadcastConfigurationMap.remove(oldName);
|
|
||||||
}
|
|
||||||
|
|
||||||
mBroadcastConfigurationMap.put(broadcastConfiguration.getName(), broadcastConfiguration);
|
|
||||||
|
|
||||||
return oldName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getRowCount()
|
public int getRowCount()
|
||||||
{
|
{
|
||||||
@@ -649,37 +695,51 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
*/
|
*/
|
||||||
private void removeOrphanedTemporaryRecordings()
|
private void removeOrphanedTemporaryRecordings()
|
||||||
{
|
{
|
||||||
Path path = SystemProperties.getInstance().getApplicationFolder(BroadcastModel.TEMPORARY_STREAM_DIRECTORY);
|
ThreadPool.SCHEDULED.submit(new Runnable()
|
||||||
|
|
||||||
if(path != null && Files.isDirectory(path))
|
|
||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
@Override
|
||||||
sb.append(TEMPORARY_STREAM_FILE_SUFFIX);
|
public void run()
|
||||||
sb.append("*.*");
|
|
||||||
|
|
||||||
try(DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path, sb.toString()))
|
|
||||||
{
|
{
|
||||||
directoryStream.forEach(new Consumer<Path>()
|
try
|
||||||
{
|
{
|
||||||
@Override
|
Path path = SystemProperties.getInstance().getApplicationFolder(BroadcastModel.TEMPORARY_STREAM_DIRECTORY);
|
||||||
public void accept(Path path)
|
|
||||||
|
if(path != null && Files.isDirectory(path))
|
||||||
{
|
{
|
||||||
try
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(TEMPORARY_STREAM_FILE_SUFFIX);
|
||||||
|
sb.append("*.*");
|
||||||
|
|
||||||
|
try(DirectoryStream<Path> directoryStream = Files.newDirectoryStream(path, sb.toString()))
|
||||||
{
|
{
|
||||||
Files.delete(path);
|
directoryStream.forEach(new Consumer<Path>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void accept(Path path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Files.delete(path);
|
||||||
|
}
|
||||||
|
catch(IOException ioe)
|
||||||
|
{
|
||||||
|
mLog.error("Couldn't delete orphaned temporary recording: " + path.toString(), ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch(IOException ioe)
|
catch(IOException ioe)
|
||||||
{
|
{
|
||||||
mLog.error("Couldn't delete orphaned temporary recording: " + path.toString(), ioe);
|
mLog.error("Error discovering orphaned temporary stream recording files", ioe);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
catch(Throwable t)
|
||||||
|
{
|
||||||
|
mLog.error("Error during cleanup of orphaned temporary streaming recording files");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch(IOException ioe)
|
});
|
||||||
{
|
|
||||||
mLog.error("Error discovering orphaned temporary stream recording files", ioe);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -743,4 +803,29 @@ public class BroadcastModel extends AbstractTableModel implements Listener<Audio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List change listener to detect broadcast configuration changes and broadcast a change event
|
||||||
|
*/
|
||||||
|
public class ConfigurationChangeListener implements ListChangeListener<BroadcastConfiguration>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public void onChanged(Change<? extends BroadcastConfiguration> change)
|
||||||
|
{
|
||||||
|
while(change.next())
|
||||||
|
{
|
||||||
|
if(change.wasUpdated())
|
||||||
|
{
|
||||||
|
for(int x = change.getFrom(); x < change.getTo(); x++)
|
||||||
|
{
|
||||||
|
BroadcastConfiguration config = change.getList().get(x);
|
||||||
|
BroadcastEvent event = new BroadcastEvent(config, BroadcastEvent.Event.CONFIGURATION_CHANGE);
|
||||||
|
process(event);
|
||||||
|
broadcast(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,270 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * ******************************************************************************
|
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
* *
|
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
|
||||||
* * it under the terms of the GNU General Public License as published by
|
|
||||||
* * the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* * (at your option) any later version.
|
|
||||||
* *
|
|
||||||
* * This program is distributed in the hope that it will be useful,
|
|
||||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* * GNU General Public License for more details.
|
|
||||||
* *
|
|
||||||
* * You should have received a copy of the GNU General Public License
|
|
||||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* * *****************************************************************************
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.audio.broadcast;
|
|
||||||
|
|
||||||
import com.jidesoft.swing.JideSplitPane;
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.gui.editor.EmptyEditor;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JPopupMenu;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.awt.event.MouseAdapter;
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
|
|
||||||
public class BroadcastPanel extends JPanel implements ActionListener, ListSelectionListener
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger( BroadcastPanel.class );
|
|
||||||
|
|
||||||
private static final String NEW_BROADCAST_CONFIGURATION = "New";
|
|
||||||
private static final String COPY_BROADCAST_CONFIGURATION = "Copy";
|
|
||||||
private static final String DELETE_BROADCAST_CONFIGURATION = "Delete";
|
|
||||||
|
|
||||||
private BroadcastModel mBroadcastModel;
|
|
||||||
private AliasModel mAliasModel;
|
|
||||||
private IconManager mIconManager;
|
|
||||||
private UserPreferences mUserPreferences;
|
|
||||||
|
|
||||||
private BroadcastStatusPanel mBroadcastStatusPanel;
|
|
||||||
private JideSplitPane mSplitPane;
|
|
||||||
private Editor<BroadcastConfiguration> mEmptyEditor = new EmptyEditor<>("Configuration:");
|
|
||||||
private Editor<BroadcastConfiguration> mEditor;
|
|
||||||
private JButton mNewButton = new JButton(NEW_BROADCAST_CONFIGURATION);
|
|
||||||
private JButton mCopyButton = new JButton(COPY_BROADCAST_CONFIGURATION);
|
|
||||||
private JButton mDeleteButton = new JButton(DELETE_BROADCAST_CONFIGURATION);
|
|
||||||
|
|
||||||
public BroadcastPanel(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager,
|
|
||||||
UserPreferences userPreferences)
|
|
||||||
{
|
|
||||||
mBroadcastModel = broadcastModel;
|
|
||||||
mAliasModel = aliasModel;
|
|
||||||
mIconManager = iconManager;
|
|
||||||
mEditor = mEmptyEditor;
|
|
||||||
mUserPreferences = userPreferences;
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("insets 0 0 0 0 ", "[grow,fill]", "[grow,fill]"));
|
|
||||||
|
|
||||||
mBroadcastStatusPanel = new BroadcastStatusPanel(mBroadcastModel, mUserPreferences,
|
|
||||||
"broadcast.panel.broadcast.status.panel");
|
|
||||||
|
|
||||||
mBroadcastStatusPanel.getTable().setAutoCreateRowSorter(true);
|
|
||||||
mBroadcastStatusPanel.getTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
mBroadcastStatusPanel.getTable().getSelectionModel().addListSelectionListener(BroadcastPanel.this);
|
|
||||||
|
|
||||||
JPanel buttonsPanel = new JPanel();
|
|
||||||
buttonsPanel.setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill][grow,fill][grow,fill]", "[]"));
|
|
||||||
|
|
||||||
mNewButton = new JButton("New ...");
|
|
||||||
mNewButton.setToolTipText("Create a new broadcast audio configuration");
|
|
||||||
mNewButton.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e)
|
|
||||||
{
|
|
||||||
JPopupMenu menu = new JPopupMenu();
|
|
||||||
|
|
||||||
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.BROADCASTIFY));
|
|
||||||
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.ICECAST_TCP));
|
|
||||||
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.ICECAST_HTTP));
|
|
||||||
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.SHOUTCAST_V1));
|
|
||||||
menu.add(new AddBroadcastConfigurationItem(BroadcastServerType.SHOUTCAST_V2));
|
|
||||||
|
|
||||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
buttonsPanel.add(mNewButton);
|
|
||||||
|
|
||||||
mCopyButton.addActionListener(this);
|
|
||||||
mCopyButton.setEnabled(false);
|
|
||||||
mCopyButton.setToolTipText("Creates a copy of the currently selected streaming configuration and adds it");
|
|
||||||
buttonsPanel.add(mCopyButton);
|
|
||||||
|
|
||||||
mDeleteButton.addActionListener(this);
|
|
||||||
mDeleteButton.setEnabled(false);
|
|
||||||
mDeleteButton.setToolTipText("Deletes the currently selected streaming configuration");
|
|
||||||
buttonsPanel.add(mDeleteButton);
|
|
||||||
|
|
||||||
JPanel listAndButtonsPanel = new JPanel();
|
|
||||||
|
|
||||||
listAndButtonsPanel.setLayout(new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill][]"));
|
|
||||||
|
|
||||||
listAndButtonsPanel.add(mBroadcastStatusPanel, "wrap");
|
|
||||||
listAndButtonsPanel.add(buttonsPanel);
|
|
||||||
|
|
||||||
mSplitPane = new JideSplitPane(JideSplitPane.HORIZONTAL_SPLIT);
|
|
||||||
mSplitPane.setDividerSize(5);
|
|
||||||
mSplitPane.setShowGripper(true);
|
|
||||||
mSplitPane.add(listAndButtonsPanel);
|
|
||||||
|
|
||||||
mSplitPane.add(mEditor);
|
|
||||||
|
|
||||||
add(mSplitPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
switch(e.getActionCommand())
|
|
||||||
{
|
|
||||||
case COPY_BROADCAST_CONFIGURATION:
|
|
||||||
BroadcastConfiguration copySelected = getSelectedBroadcastConfiguration();
|
|
||||||
mBroadcastModel.cloneBroadcastConfiguration(copySelected);
|
|
||||||
break;
|
|
||||||
case DELETE_BROADCAST_CONFIGURATION:
|
|
||||||
BroadcastConfiguration deleteSelected = getSelectedBroadcastConfiguration();
|
|
||||||
|
|
||||||
if(deleteSelected != null)
|
|
||||||
{
|
|
||||||
int choice = JOptionPane.showConfirmDialog(BroadcastPanel.this, "Do you want to delete broadcast\n" +
|
|
||||||
" configuration " + deleteSelected.getName() + "?", "Delete Broadcast Configuration?",
|
|
||||||
JOptionPane.YES_NO_OPTION);
|
|
||||||
|
|
||||||
if(choice == JOptionPane.YES_OPTION)
|
|
||||||
{
|
|
||||||
mBroadcastModel.removeBroadcastConfiguration(deleteSelected);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the selected configuration
|
|
||||||
*/
|
|
||||||
private BroadcastConfiguration getSelectedBroadcastConfiguration()
|
|
||||||
{
|
|
||||||
int viewRow = mBroadcastStatusPanel.getTable().getSelectedRow();
|
|
||||||
|
|
||||||
if(viewRow >= 0)
|
|
||||||
{
|
|
||||||
int modelRow = mBroadcastStatusPanel.getTable().convertRowIndexToModel(viewRow);
|
|
||||||
|
|
||||||
if(modelRow >= 0)
|
|
||||||
{
|
|
||||||
return mBroadcastModel.getConfigurationAt(modelRow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void valueChanged(ListSelectionEvent e)
|
|
||||||
{
|
|
||||||
if (!e.getValueIsAdjusting())
|
|
||||||
{
|
|
||||||
BroadcastConfiguration selectedConfiguration = getSelectedBroadcastConfiguration();
|
|
||||||
|
|
||||||
//Enable buttons accordingly
|
|
||||||
mCopyButton.setEnabled(selectedConfiguration != null);
|
|
||||||
mDeleteButton.setEnabled(selectedConfiguration != null);
|
|
||||||
|
|
||||||
if (mEditor.isModified())
|
|
||||||
{
|
|
||||||
int option = JOptionPane.showConfirmDialog(
|
|
||||||
BroadcastPanel.this,
|
|
||||||
"Configuration settings have changed. Do you want to save these changes?",
|
|
||||||
"Save Changes?",
|
|
||||||
JOptionPane.YES_NO_OPTION,
|
|
||||||
JOptionPane.QUESTION_MESSAGE);
|
|
||||||
|
|
||||||
if (option == JOptionPane.YES_OPTION)
|
|
||||||
{
|
|
||||||
mEditor.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mSplitPane.removePane(mEditor);
|
|
||||||
|
|
||||||
if (selectedConfiguration != null)
|
|
||||||
{
|
|
||||||
mEditor = BroadcastFactory.getEditor(mUserPreferences, selectedConfiguration, mBroadcastModel,
|
|
||||||
mAliasModel, mIconManager);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mEditor = mEmptyEditor;
|
|
||||||
}
|
|
||||||
|
|
||||||
mSplitPane.add(mEditor);
|
|
||||||
|
|
||||||
revalidate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AddBroadcastConfigurationItem extends JMenuItem
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private BroadcastServerType mBroadcastServerType;
|
|
||||||
|
|
||||||
public AddBroadcastConfigurationItem(BroadcastServerType type)
|
|
||||||
{
|
|
||||||
super(type.toString(), mIconManager.getScaledIcon(type.getIconPath(), 14));
|
|
||||||
|
|
||||||
mBroadcastServerType = type;
|
|
||||||
|
|
||||||
setToolTipText("Add a new " + type.toString() + " audio stream configuration");
|
|
||||||
|
|
||||||
addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
final BroadcastConfiguration configuration =
|
|
||||||
BroadcastFactory.getConfiguration(mBroadcastServerType, BroadcastFormat.MP3);
|
|
||||||
|
|
||||||
if(configuration != null)
|
|
||||||
{
|
|
||||||
mBroadcastModel.addBroadcastConfiguration(configuration);
|
|
||||||
|
|
||||||
int modelRow = mBroadcastModel.getRowForConfiguration(configuration);
|
|
||||||
int tableRow = mBroadcastStatusPanel.getTable().convertRowIndexToView(modelRow);
|
|
||||||
mBroadcastStatusPanel.getTable().changeSelection(tableRow, 0, false, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* * ******************************************************************************
|
||||||
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
|
* *
|
||||||
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.github.dsheirer.audio.broadcast;
|
||||||
|
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.ObjectProperty;
|
||||||
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.util.Callback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Composite observable object that joins a broadcast configuration and (optional) constructed audio broadcaster
|
||||||
|
*/
|
||||||
|
public class ConfiguredBroadcast
|
||||||
|
{
|
||||||
|
private BroadcastConfiguration mBroadcastConfiguration;
|
||||||
|
private AudioBroadcaster mAudioBroadcaster;
|
||||||
|
private ObjectProperty<BroadcastState> mBroadcastState = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance
|
||||||
|
* @param broadcastConfiguration for the instance
|
||||||
|
*/
|
||||||
|
public ConfiguredBroadcast(BroadcastConfiguration broadcastConfiguration)
|
||||||
|
{
|
||||||
|
mBroadcastConfiguration = broadcastConfiguration;
|
||||||
|
mBroadcastConfiguration.validProperty().addListener((observable, oldValue, newValue) -> updateBroadcastState());
|
||||||
|
updateBroadcastState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration for this broadcast
|
||||||
|
*/
|
||||||
|
public BroadcastConfiguration getBroadcastConfiguration()
|
||||||
|
{
|
||||||
|
return mBroadcastConfiguration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enabled state of the configuration
|
||||||
|
*/
|
||||||
|
public BooleanProperty enabledProperty()
|
||||||
|
{
|
||||||
|
return mBroadcastConfiguration.enabledProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the broadcast configuration
|
||||||
|
*/
|
||||||
|
public StringProperty nameProperty()
|
||||||
|
{
|
||||||
|
return mBroadcastConfiguration.nameProperty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Server type for the broadcast configuration
|
||||||
|
*/
|
||||||
|
public BroadcastServerType getBroadcastServerType()
|
||||||
|
{
|
||||||
|
return mBroadcastConfiguration.getBroadcastServerType();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Broadcast state of the configured audio broadcaster (optional)
|
||||||
|
*/
|
||||||
|
public ObjectProperty<BroadcastState> broadcastStateProperty()
|
||||||
|
{
|
||||||
|
return mBroadcastState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the audio broadcaster
|
||||||
|
* @param audioBroadcaster to use for this configuration
|
||||||
|
*/
|
||||||
|
public void setAudioBroadcaster(AudioBroadcaster audioBroadcaster)
|
||||||
|
{
|
||||||
|
mBroadcastState.unbind();
|
||||||
|
mAudioBroadcaster = audioBroadcaster;
|
||||||
|
|
||||||
|
if(audioBroadcaster != null)
|
||||||
|
{
|
||||||
|
mBroadcastState.bind(mAudioBroadcaster.broadcastStateProperty());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateBroadcastState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateBroadcastState()
|
||||||
|
{
|
||||||
|
if(!mBroadcastState.isBound())
|
||||||
|
{
|
||||||
|
if(mBroadcastConfiguration.isValid())
|
||||||
|
{
|
||||||
|
mBroadcastState.setValue(BroadcastState.READY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mBroadcastState.setValue(BroadcastState.CONFIGURATION_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional audio broadcaster created from the configuration
|
||||||
|
*/
|
||||||
|
public AudioBroadcaster getAudioBroadcaster()
|
||||||
|
{
|
||||||
|
return mAudioBroadcaster;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
|
||||||
|
*/
|
||||||
|
public static Callback<ConfiguredBroadcast, Observable[]> extractor()
|
||||||
|
{
|
||||||
|
return (ConfiguredBroadcast b) -> new Observable[] {b.nameProperty(), b.enabledProperty(),
|
||||||
|
b.broadcastStateProperty(), b.getBroadcastConfiguration().validProperty()};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,24 @@
|
|||||||
/*******************************************************************************
|
/*
|
||||||
* sdrtrunk
|
|
||||||
* 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
*/
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast.broadcastify;
|
package io.github.dsheirer.audio.broadcast.broadcastify;
|
||||||
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
@@ -23,9 +26,14 @@ import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
|||||||
import io.github.dsheirer.audio.broadcast.BroadcastFormat;
|
import io.github.dsheirer.audio.broadcast.BroadcastFormat;
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
||||||
import io.github.dsheirer.audio.broadcast.icecast.IcecastTCPConfiguration;
|
import io.github.dsheirer.audio.broadcast.icecast.IcecastTCPConfiguration;
|
||||||
|
import io.github.dsheirer.rrapi.type.UserFeedBroadcast;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class BroadcastifyConfiguration extends IcecastTCPConfiguration
|
public class BroadcastifyConfiguration extends IcecastTCPConfiguration
|
||||||
{
|
{
|
||||||
|
private final static Logger mLog = LoggerFactory.getLogger(BroadcastifyConfiguration.class);
|
||||||
|
|
||||||
private int mFeedID;
|
private int mFeedID;
|
||||||
|
|
||||||
public BroadcastifyConfiguration()
|
public BroadcastifyConfiguration()
|
||||||
@@ -48,6 +56,27 @@ public class BroadcastifyConfiguration extends IcecastTCPConfiguration
|
|||||||
setSampleRate(8000);
|
setSampleRate(8000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BroadcastifyConfiguration from(UserFeedBroadcast userFeedBroadcast)
|
||||||
|
{
|
||||||
|
BroadcastifyConfiguration config = new BroadcastifyConfiguration(BroadcastFormat.MP3);
|
||||||
|
config.setName(userFeedBroadcast.getDescription());
|
||||||
|
config.setHost(userFeedBroadcast.getHostname());
|
||||||
|
config.setMountPoint(userFeedBroadcast.getMount());
|
||||||
|
config.setFeedID(userFeedBroadcast.getFeedId());
|
||||||
|
config.setPassword(userFeedBroadcast.getPassword());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
config.setPort(Integer.parseInt(userFeedBroadcast.getPort()));
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
mLog.error("Error creating broadcastify configuration from radio reference user feed instance");
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BroadcastConfiguration copyOf()
|
public BroadcastConfiguration copyOf()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,408 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * ******************************************************************************
|
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
* *
|
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
|
||||||
* * it under the terms of the GNU General Public License as published by
|
|
||||||
* * the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* * (at your option) any later version.
|
|
||||||
* *
|
|
||||||
* * This program is distributed in the hope that it will be useful,
|
|
||||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* * GNU General Public License for more details.
|
|
||||||
* *
|
|
||||||
* * You should have received a copy of the GNU General Public License
|
|
||||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* * *****************************************************************************
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.audio.broadcast.broadcastify;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastEvent;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
|
||||||
import io.github.dsheirer.rrapi.type.UserFeedBroadcast;
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JSlider;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class BroadcastifyConfigurationEditor extends BroadcastConfigurationEditor implements Listener<UserFeedBroadcast>
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(BroadcastifyConfigurationEditor.class);
|
|
||||||
|
|
||||||
private static final int ONE_MINUTE_MS = 60000;
|
|
||||||
|
|
||||||
private JTextField mName;
|
|
||||||
private JTextField mServer;
|
|
||||||
private JTextField mPort;
|
|
||||||
private JTextField mMountPoint;
|
|
||||||
private JTextField mPassword;
|
|
||||||
private JTextField mFeedID;
|
|
||||||
private JSlider mDelay;
|
|
||||||
private JLabel mDelayValue;
|
|
||||||
private JSlider mMaximumRecordingAge;
|
|
||||||
private JLabel mMaximumRecordingAgeValue;
|
|
||||||
private JCheckBox mEnabled;
|
|
||||||
private JButton mSaveButton;
|
|
||||||
private JButton mResetButton;
|
|
||||||
private UserPreferences mUserPreferences;
|
|
||||||
|
|
||||||
public BroadcastifyConfigurationEditor(UserPreferences userPreferences, BroadcastModel broadcastModel,
|
|
||||||
AliasModel aliasModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
super(broadcastModel, aliasModel, iconManager);
|
|
||||||
mUserPreferences = userPreferences;
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[align right][grow,fill]",
|
|
||||||
"[][][][][][][][][][][][][][][grow,fill]"));
|
|
||||||
setPreferredSize(new Dimension(150, 400));
|
|
||||||
|
|
||||||
|
|
||||||
JLabel channelLabel = new JLabel("Broadcastify Stream");
|
|
||||||
|
|
||||||
ImageIcon broadcastifyIcon = mIconManager.getScaledIcon(BroadcastServerType.BROADCASTIFY.getIconPath(), 25);
|
|
||||||
channelLabel.setIcon(broadcastifyIcon);
|
|
||||||
add(channelLabel, "span, align center");
|
|
||||||
|
|
||||||
JButton lookupButton = new JButton("Lookup ...");
|
|
||||||
lookupButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
final UserFeedSelectionDialog dialog = new UserFeedSelectionDialog(mUserPreferences,BroadcastifyConfigurationEditor.this);
|
|
||||||
|
|
||||||
EventQueue.invokeLater(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
dialog.setLocationRelativeTo(BroadcastifyConfigurationEditor.this);
|
|
||||||
dialog.setVisible(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
add(new JLabel(""));
|
|
||||||
add(lookupButton, "grow,wrap");
|
|
||||||
|
|
||||||
add(new JLabel("Name:"));
|
|
||||||
mName = new JTextField();
|
|
||||||
mName.getDocument().addDocumentListener(this);
|
|
||||||
mName.setToolTipText("Unique name for this stream");
|
|
||||||
add(mName);
|
|
||||||
|
|
||||||
add(new JLabel("Server:"));
|
|
||||||
mServer = new JTextField();
|
|
||||||
mServer.getDocument().addDocumentListener(this);
|
|
||||||
mServer.setToolTipText("Server address (e.g. audio3.broadcastify.com). See MyBCFY feed details, Technicals tab");
|
|
||||||
add(mServer);
|
|
||||||
|
|
||||||
add(new JLabel("Port:"));
|
|
||||||
mPort = new JTextField();
|
|
||||||
mPort.getDocument().addDocumentListener(this);
|
|
||||||
mPort.setToolTipText("Server port number (e.g. 80). See MyBCFY feed details, Technicals tab");
|
|
||||||
add(mPort);
|
|
||||||
|
|
||||||
add(new JLabel("Mount:"));
|
|
||||||
mMountPoint = new JTextField();
|
|
||||||
mMountPoint.getDocument().addDocumentListener(this);
|
|
||||||
mMountPoint.setToolTipText("Mount point (e.g. \\awlkejrlkjsd). See MyBCFY feed details, Technicals tab");
|
|
||||||
add(mMountPoint);
|
|
||||||
|
|
||||||
add(new JLabel("Password:"));
|
|
||||||
mPassword = new JTextField();
|
|
||||||
mPassword.getDocument().addDocumentListener(this);
|
|
||||||
mPassword.setToolTipText("Password. See MyBCFY feed details, Technicals tab");
|
|
||||||
add(mPassword);
|
|
||||||
|
|
||||||
add(new JLabel("Feed ID:"));
|
|
||||||
mFeedID = new JTextField();
|
|
||||||
mFeedID.getDocument().addDocumentListener(this);
|
|
||||||
mFeedID.setToolTipText("Feed ID (optional). See MyBCFY feed details");
|
|
||||||
add(mFeedID);
|
|
||||||
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mDelayValue = new JLabel("0 Minutes");
|
|
||||||
add(mDelayValue);
|
|
||||||
|
|
||||||
add(new JLabel("Delay:"));
|
|
||||||
mDelay = new JSlider(0, 60, 0);
|
|
||||||
mDelay.setMajorTickSpacing(10);
|
|
||||||
mDelay.setMinorTickSpacing(5);
|
|
||||||
mDelay.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
mDelayValue.setText(mDelay.getValue() + " Minutes");
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mDelay.setToolTipText("Audio broadcast delay in minutes");
|
|
||||||
add(mDelay);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mMaximumRecordingAgeValue = new JLabel("1 Minute");
|
|
||||||
add(mMaximumRecordingAgeValue);
|
|
||||||
|
|
||||||
add(new JLabel("Age Limit:"));
|
|
||||||
mMaximumRecordingAge = new JSlider(1,60,5);
|
|
||||||
mMaximumRecordingAge.setMajorTickSpacing(10);
|
|
||||||
mMaximumRecordingAge.setMinorTickSpacing(5);
|
|
||||||
mMaximumRecordingAge.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
int value = mMaximumRecordingAge.getValue();
|
|
||||||
|
|
||||||
mMaximumRecordingAgeValue.setText(value + " Minute" + (value > 1 ? "s" : ""));
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mMaximumRecordingAge.setToolTipText("Maximum recording age (in addition to delay) to stream");
|
|
||||||
add(mMaximumRecordingAge);
|
|
||||||
|
|
||||||
mEnabled = new JCheckBox("Enabled");
|
|
||||||
mEnabled.setToolTipText("Enable (checked) or disable this stream");
|
|
||||||
mEnabled.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(new JLabel());
|
|
||||||
add(mEnabled);
|
|
||||||
|
|
||||||
mSaveButton = new JButton("Save");
|
|
||||||
mSaveButton.setEnabled(false);
|
|
||||||
mSaveButton.setToolTipText("Click to save configuration information");
|
|
||||||
mSaveButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mSaveButton);
|
|
||||||
|
|
||||||
mResetButton = new JButton("Reset");
|
|
||||||
mResetButton.setEnabled(false);
|
|
||||||
mResetButton.setToolTipText("Click to reset any changes you've made\n since the last save");
|
|
||||||
mResetButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(false);
|
|
||||||
setItem(getItem());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mResetButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModified(boolean modified)
|
|
||||||
{
|
|
||||||
super.setModified(modified);
|
|
||||||
|
|
||||||
mSaveButton.setEnabled(modified);
|
|
||||||
mResetButton.setEnabled(modified);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(BroadcastConfiguration item)
|
|
||||||
{
|
|
||||||
super.setItem(item);
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
BroadcastifyConfiguration config = (BroadcastifyConfiguration) getItem();
|
|
||||||
|
|
||||||
mName.setText(config.getName());
|
|
||||||
mServer.setText(config.getHost());
|
|
||||||
mPort.setText(config.getPort() != 0 ? String.valueOf(config.getPort()) : null);
|
|
||||||
mMountPoint.setText(config.getMountPoint());
|
|
||||||
mPassword.setText(config.getPassword());
|
|
||||||
mFeedID.setText(String.valueOf(config.getFeedID()));
|
|
||||||
mDelay.setValue((int) (config.getDelay() / ONE_MINUTE_MS));
|
|
||||||
mMaximumRecordingAge.setValue((int)config.getMaximumRecordingAge() / ONE_MINUTE_MS);
|
|
||||||
mEnabled.setSelected(config.isEnabled());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mName.setText(null);
|
|
||||||
mServer.setText(null);
|
|
||||||
mPort.setText(null);
|
|
||||||
mMountPoint.setText(null);
|
|
||||||
mPassword.setText(null);
|
|
||||||
mFeedID.setText(null);
|
|
||||||
mDelay.setValue(0);
|
|
||||||
mMaximumRecordingAge.setValue(1);
|
|
||||||
mEnabled.setSelected(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
BroadcastifyConfiguration config = (BroadcastifyConfiguration) getItem();
|
|
||||||
|
|
||||||
if(validateConfiguration())
|
|
||||||
{
|
|
||||||
updateConfigurationName(config, mName.getText());
|
|
||||||
config.setHost(mServer.getText());
|
|
||||||
config.setPort(getPort());
|
|
||||||
config.setMountPoint(mMountPoint.getText());
|
|
||||||
config.setPassword(mPassword.getText());
|
|
||||||
config.setFeedID(getFeedID());
|
|
||||||
config.setDelay(mDelay.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setMaximumRecordingAge(mMaximumRecordingAge.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setEnabled(mEnabled.isSelected());
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
mBroadcastModel.process(new BroadcastEvent(getItem(), BroadcastEvent.Event.CONFIGURATION_CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the user specified values in the controls prior to saving them to the configuration
|
|
||||||
*/
|
|
||||||
private boolean validateConfiguration()
|
|
||||||
{
|
|
||||||
String name = mName.getText();
|
|
||||||
|
|
||||||
//A unique stream name is required
|
|
||||||
if(!mBroadcastModel.isUniqueName(name, getItem()))
|
|
||||||
{
|
|
||||||
String message = (name == null || name.isEmpty()) ?
|
|
||||||
"Please specify a stream name." : "Stream name " + name +
|
|
||||||
"is already in use.\nPlease choose another name.";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(BroadcastifyConfigurationEditor.this,
|
|
||||||
message, "Invalid Stream Name", JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
mName.requestFocus();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Server address is optional, but required
|
|
||||||
if(!validateTextField(mServer, "Invalid Server Address", "Please specify a server address."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port is optional, but required
|
|
||||||
if(!validateIntegerTextField(mPort, "Invalid Port Number", "Please specify a port number (1 <> 65535)", 1, 65535))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Mount Point is optional, but required
|
|
||||||
if(!validateTextField(mMountPoint, "Invalid Mount Point", "Please specify a mount point."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Password is optional, but required
|
|
||||||
if(!validateTextField(mPassword, "Invalid Password", "Please specify a password."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an Integer from the port text control or returns 0 if the control doesn't contain an integer value.
|
|
||||||
*/
|
|
||||||
private int getPort()
|
|
||||||
{
|
|
||||||
String port = mPort.getText();
|
|
||||||
|
|
||||||
if(port != null && !port.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(port);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an Integer from the port text control or returns 0 if the control doesn't contain an integer value.
|
|
||||||
*/
|
|
||||||
private int getFeedID()
|
|
||||||
{
|
|
||||||
String feedID = mFeedID.getText();
|
|
||||||
|
|
||||||
if(feedID != null && !feedID.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(feedID);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive(UserFeedBroadcast userFeedBroadcast)
|
|
||||||
{
|
|
||||||
mName.setText(userFeedBroadcast.getDescription());
|
|
||||||
mServer.setText(userFeedBroadcast.getHostname());
|
|
||||||
mPort.setText(userFeedBroadcast.getPort());
|
|
||||||
mMountPoint.setText(userFeedBroadcast.getMount());
|
|
||||||
mPassword.setText(userFeedBroadcast.getPassword());
|
|
||||||
mFeedID.setText(String.valueOf(userFeedBroadcast.getFeedId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,343 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * ******************************************************************************
|
|
||||||
* * Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
* *
|
|
||||||
* * This program is free software: you can redistribute it and/or modify
|
|
||||||
* * it under the terms of the GNU General Public License as published by
|
|
||||||
* * the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* * (at your option) any later version.
|
|
||||||
* *
|
|
||||||
* * This program is distributed in the hope that it will be useful,
|
|
||||||
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* * GNU General Public License for more details.
|
|
||||||
* *
|
|
||||||
* * You should have received a copy of the GNU General Public License
|
|
||||||
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* * *****************************************************************************
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.audio.broadcast.broadcastify;
|
|
||||||
|
|
||||||
import com.google.common.eventbus.Subscribe;
|
|
||||||
import io.github.dsheirer.eventbus.MyEventBus;
|
|
||||||
import io.github.dsheirer.preference.PreferenceType;
|
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
|
||||||
import io.github.dsheirer.rrapi.RadioReferenceException;
|
|
||||||
import io.github.dsheirer.rrapi.RadioReferenceService;
|
|
||||||
import io.github.dsheirer.rrapi.type.AuthorizationInformation;
|
|
||||||
import io.github.dsheirer.rrapi.type.UserFeedBroadcast;
|
|
||||||
import io.github.dsheirer.rrapi.type.UserInfo;
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JDialog;
|
|
||||||
import javax.swing.JFrame;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JList;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.ListCellRenderer;
|
|
||||||
import javax.swing.event.DocumentEvent;
|
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
import java.awt.BorderLayout;
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.EventQueue;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class UserFeedSelectionDialog extends JDialog implements DocumentListener
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger( UserFeedSelectionDialog.class );
|
|
||||||
|
|
||||||
public static final String SDRTRUNK_APP_KEY = "88969092";
|
|
||||||
|
|
||||||
private Listener<UserFeedBroadcast> mListener;
|
|
||||||
private UserPreferences mUserPreferences;
|
|
||||||
private JTextField mUserNameText;
|
|
||||||
private JTextField mPasswordText;
|
|
||||||
private JCheckBox mSaveCredentialsCheckBox;
|
|
||||||
private JButton mClearStoredCredentialsButton;
|
|
||||||
private JButton mLookupButton;
|
|
||||||
private JList mUserFeedBroadcastList;
|
|
||||||
private JButton mOKButton;
|
|
||||||
|
|
||||||
public UserFeedSelectionDialog(UserPreferences userPreferences, Listener<UserFeedBroadcast> listener)
|
|
||||||
{
|
|
||||||
mUserPreferences = userPreferences;
|
|
||||||
mListener = listener;
|
|
||||||
|
|
||||||
//Register to receive radio reference preferences updates
|
|
||||||
MyEventBus.getEventBus().register(this);
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
JPanel panel = new JPanel();
|
|
||||||
panel.setLayout(new MigLayout("","[align right,grow,fill][align left,grow,fill][]","[][][][][][grow][]"));
|
|
||||||
|
|
||||||
panel.add(new JLabel("Please enter your credentials"), "align left,span");
|
|
||||||
|
|
||||||
panel.add(new JLabel("User Name:"));
|
|
||||||
mUserNameText = new JTextField();
|
|
||||||
String storedUserName = mUserPreferences.getRadioReferencePreference().getUserName();
|
|
||||||
if(storedUserName != null)
|
|
||||||
{
|
|
||||||
mUserNameText.setText(storedUserName);
|
|
||||||
}
|
|
||||||
mUserNameText.getDocument().addDocumentListener(this);
|
|
||||||
panel.add(mUserNameText, "wrap");
|
|
||||||
|
|
||||||
panel.add(new JLabel("Password:"));
|
|
||||||
mPasswordText = new JTextField();
|
|
||||||
String storedPassword = mUserPreferences.getRadioReferencePreference().getPassword();
|
|
||||||
if(storedPassword != null)
|
|
||||||
{
|
|
||||||
mPasswordText.setText(storedPassword);
|
|
||||||
}
|
|
||||||
mPasswordText.getDocument().addDocumentListener(this);
|
|
||||||
panel.add(mPasswordText, "wrap");
|
|
||||||
|
|
||||||
mSaveCredentialsCheckBox = new JCheckBox("Store Credentials");
|
|
||||||
mSaveCredentialsCheckBox.setSelected(mUserPreferences.getRadioReferencePreference().isStoreCredentials());
|
|
||||||
mSaveCredentialsCheckBox.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
//If user unchecks box and there are stored credentials, prompt to clear them
|
|
||||||
if(!mSaveCredentialsCheckBox.isSelected() && mUserPreferences.getRadioReferencePreference().hasStoredCredentials())
|
|
||||||
{
|
|
||||||
int choice = JOptionPane.showOptionDialog(UserFeedSelectionDialog.this,
|
|
||||||
"Would you like to remove previously stored credentials from this computer?",
|
|
||||||
"Clear Stored Credentials?", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
|
|
||||||
null, null, 0);
|
|
||||||
|
|
||||||
if(choice == JOptionPane.YES_OPTION)
|
|
||||||
{
|
|
||||||
mUserPreferences.getRadioReferencePreference().removeStoreCredentials();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
panel.add(mSaveCredentialsCheckBox);
|
|
||||||
|
|
||||||
mClearStoredCredentialsButton = new JButton("Remove");
|
|
||||||
mClearStoredCredentialsButton.setToolTipText("Clear stored credentials");
|
|
||||||
mClearStoredCredentialsButton.setEnabled(mUserPreferences.getRadioReferencePreference().hasStoredCredentials());
|
|
||||||
mClearStoredCredentialsButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
mUserPreferences.getRadioReferencePreference().removeStoreCredentials();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
panel.add(mClearStoredCredentialsButton, "wrap");
|
|
||||||
|
|
||||||
mLookupButton = new JButton("Get Feeds");
|
|
||||||
mLookupButton.setEnabled(storedPassword != null && storedPassword != null);
|
|
||||||
mLookupButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
mLookupButton.setEnabled(false);
|
|
||||||
|
|
||||||
EventQueue.invokeLater(new Runnable()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AuthorizationInformation authorizationInformation = new AuthorizationInformation(SDRTRUNK_APP_KEY,
|
|
||||||
mUserNameText.getText(), mPasswordText.getText());
|
|
||||||
|
|
||||||
mLog.debug("User:" + authorizationInformation.getUserName() + " Pass:" + authorizationInformation.getPassword() + " Key:" + authorizationInformation.getApplicationKey());
|
|
||||||
|
|
||||||
RadioReferenceService service = new RadioReferenceService(authorizationInformation);
|
|
||||||
UserInfo userInfo = service.getUserInfo();
|
|
||||||
mLog.info("RR User:" + userInfo.getUserName() + " Expiration Date:" + userInfo.getExpirationDate());
|
|
||||||
List<UserFeedBroadcast> feeds = service.getUserFeeds();
|
|
||||||
|
|
||||||
mUserFeedBroadcastList.setListData(feeds.toArray(new UserFeedBroadcast[0]));
|
|
||||||
}
|
|
||||||
catch(RadioReferenceException rre)
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog(UserFeedSelectionDialog.this,
|
|
||||||
"Unable to create radio reference web service client. See log file.",
|
|
||||||
"Error", JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
mLog.error("Error creating the radio reference web service client", rre);
|
|
||||||
}
|
|
||||||
|
|
||||||
mLookupButton.setEnabled(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
panel.add(mLookupButton,"grow,span");
|
|
||||||
|
|
||||||
mUserFeedBroadcastList = new JList();
|
|
||||||
mUserFeedBroadcastList.setVisibleRowCount(3);
|
|
||||||
mUserFeedBroadcastList.setLayoutOrientation(JList.VERTICAL);
|
|
||||||
mUserFeedBroadcastList.setCellRenderer(new CellRenderer());
|
|
||||||
mUserFeedBroadcastList.addListSelectionListener(new ListSelectionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void valueChanged(ListSelectionEvent e)
|
|
||||||
{
|
|
||||||
mOKButton.setEnabled(mUserFeedBroadcastList.getSelectedValue() != null);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JScrollPane listScrollPane = new JScrollPane(mUserFeedBroadcastList);
|
|
||||||
panel.add(listScrollPane, "grow,span");
|
|
||||||
|
|
||||||
mOKButton = new JButton("Ok");
|
|
||||||
mOKButton.setEnabled(false);
|
|
||||||
mOKButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
if(mListener != null)
|
|
||||||
{
|
|
||||||
storeCredentials();
|
|
||||||
mListener.receive((UserFeedBroadcast)mUserFeedBroadcastList.getSelectedValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
panel.add(mOKButton,"grow");
|
|
||||||
|
|
||||||
JButton cancelButton = new JButton("Cancel");
|
|
||||||
cancelButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
dispose();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
panel.add(cancelButton, "wrap");
|
|
||||||
|
|
||||||
setTitle("Broadcastify Feed Lookup");
|
|
||||||
setLayout(new BorderLayout());
|
|
||||||
add(panel, BorderLayout.CENTER);
|
|
||||||
setSize(400,450);
|
|
||||||
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
|
|
||||||
setModalityType(ModalityType.APPLICATION_MODAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stores login credentials in the user preferences
|
|
||||||
*/
|
|
||||||
private void storeCredentials()
|
|
||||||
{
|
|
||||||
boolean store = mSaveCredentialsCheckBox.isSelected();
|
|
||||||
mUserPreferences.getRadioReferencePreference().setStoreCredentials(store);
|
|
||||||
|
|
||||||
if(store)
|
|
||||||
{
|
|
||||||
String userName = mUserNameText.getText();
|
|
||||||
|
|
||||||
if(userName != null)
|
|
||||||
{
|
|
||||||
mUserPreferences.getRadioReferencePreference().setUserName(userName);
|
|
||||||
}
|
|
||||||
|
|
||||||
String password = mPasswordText.getText();
|
|
||||||
|
|
||||||
if(password != null)
|
|
||||||
{
|
|
||||||
mUserPreferences.getRadioReferencePreference().setPassword(password);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateButtons()
|
|
||||||
{
|
|
||||||
String username = mUserNameText.getText();
|
|
||||||
String password = mPasswordText.getText();
|
|
||||||
|
|
||||||
mLookupButton.setEnabled(username != null && !username.isEmpty() && password != null && !password.isEmpty());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertUpdate(DocumentEvent e)
|
|
||||||
{
|
|
||||||
updateButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUpdate(DocumentEvent e)
|
|
||||||
{
|
|
||||||
updateButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(DocumentEvent e)
|
|
||||||
{
|
|
||||||
updateButtons();
|
|
||||||
}
|
|
||||||
|
|
||||||
private class CellRenderer extends JLabel implements ListCellRenderer<UserFeedBroadcast>
|
|
||||||
{
|
|
||||||
public CellRenderer()
|
|
||||||
{
|
|
||||||
setOpaque(true);
|
|
||||||
setHorizontalAlignment(LEFT);
|
|
||||||
setVerticalAlignment(CENTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getListCellRendererComponent(JList<? extends UserFeedBroadcast> list,
|
|
||||||
UserFeedBroadcast value,
|
|
||||||
int index,
|
|
||||||
boolean isSelected,
|
|
||||||
boolean cellHasFocus)
|
|
||||||
{
|
|
||||||
if (isSelected)
|
|
||||||
{
|
|
||||||
setBackground(list.getSelectionBackground());
|
|
||||||
setForeground(list.getSelectionForeground());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setBackground(list.getBackground());
|
|
||||||
setForeground(list.getForeground());
|
|
||||||
}
|
|
||||||
|
|
||||||
setText(value.getDescription());
|
|
||||||
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void preferenceUpdated(PreferenceType preferenceType)
|
|
||||||
{
|
|
||||||
if(preferenceType == PreferenceType.RADIO_REFERENCE)
|
|
||||||
{
|
|
||||||
//Update the store-credentials checkbox only, so we don't change the username or password currently displayed
|
|
||||||
mSaveCredentialsCheckBox.setSelected(mUserPreferences.getRadioReferencePreference().isStoreCredentials());
|
|
||||||
mClearStoredCredentialsButton.setEnabled(mUserPreferences.getRadioReferencePreference().hasStoredCredentials());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,383 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* 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 <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast.icecast;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastEvent;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JSlider;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class IcecastHTTPConfigurationEditor extends BroadcastConfigurationEditor
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger( IcecastHTTPConfigurationEditor.class );
|
|
||||||
|
|
||||||
private static final int ONE_MINUTE_MS = 60000;
|
|
||||||
|
|
||||||
private JTextField mName;
|
|
||||||
private JTextField mServer;
|
|
||||||
private JTextField mPort;
|
|
||||||
private JTextField mMountPoint;
|
|
||||||
private JTextField mUsername;
|
|
||||||
private JTextField mPassword;
|
|
||||||
private JTextField mDescription;
|
|
||||||
private JTextField mGenre;
|
|
||||||
private JCheckBox mPublic;
|
|
||||||
private JSlider mDelay;
|
|
||||||
private JLabel mDelayValue;
|
|
||||||
private JSlider mMaximumRecordingAge;
|
|
||||||
private JLabel mMaximumRecordingAgeValue;
|
|
||||||
private JCheckBox mEnabled;
|
|
||||||
private JButton mSaveButton;
|
|
||||||
private JButton mResetButton;
|
|
||||||
|
|
||||||
public IcecastHTTPConfigurationEditor(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
super(broadcastModel, aliasModel, iconManager);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[align right][grow,fill]",
|
|
||||||
"[][][][][][][][][][][][][][][][][grow,fill]" ) );
|
|
||||||
setPreferredSize(new Dimension(150,400));
|
|
||||||
|
|
||||||
JLabel channelLabel = new JLabel("Icecast 2 (v2.4+) Stream");
|
|
||||||
|
|
||||||
ImageIcon icon = mIconManager.getScaledIcon(BroadcastServerType.ICECAST_HTTP.getIconPath(), 25);
|
|
||||||
channelLabel.setIcon(icon);
|
|
||||||
|
|
||||||
add(channelLabel, "span, align center");
|
|
||||||
|
|
||||||
add(new JLabel("Name:"));
|
|
||||||
mName = new JTextField();
|
|
||||||
mName.getDocument().addDocumentListener(this);
|
|
||||||
mName.setToolTipText("Unique name for this stream");
|
|
||||||
add(mName);
|
|
||||||
|
|
||||||
add(new JLabel("Server:"));
|
|
||||||
mServer = new JTextField();
|
|
||||||
mServer.getDocument().addDocumentListener(this);
|
|
||||||
mServer.setToolTipText("Server address (e.g. audio1.icecast.com or localhost)");
|
|
||||||
add(mServer);
|
|
||||||
|
|
||||||
add(new JLabel("Port:"));
|
|
||||||
mPort = new JTextField();
|
|
||||||
mPort.getDocument().addDocumentListener(this);
|
|
||||||
mPort.setToolTipText("Server port number (e.g. 80)");
|
|
||||||
add(mPort);
|
|
||||||
|
|
||||||
add(new JLabel("Mount:"));
|
|
||||||
mMountPoint = new JTextField();
|
|
||||||
mMountPoint.getDocument().addDocumentListener(this);
|
|
||||||
mMountPoint.setToolTipText("Mount point (e.g. /12345)");
|
|
||||||
add(mMountPoint);
|
|
||||||
|
|
||||||
add(new JLabel("User Name:"));
|
|
||||||
mUsername = new JTextField();
|
|
||||||
mUsername.getDocument().addDocumentListener(this);
|
|
||||||
mUsername.setToolTipText("User name for the stream. Default: source");
|
|
||||||
add(mUsername);
|
|
||||||
|
|
||||||
add(new JLabel("Password:"));
|
|
||||||
mPassword = new JTextField();
|
|
||||||
mPassword.getDocument().addDocumentListener(this);
|
|
||||||
mPassword.setToolTipText("Password for the stream");
|
|
||||||
add(mPassword);
|
|
||||||
|
|
||||||
add(new JLabel("Description:"));
|
|
||||||
mDescription = new JTextField();
|
|
||||||
mDescription.getDocument().addDocumentListener(this);
|
|
||||||
mDescription.setToolTipText("Description of the stream contents");
|
|
||||||
add(mDescription);
|
|
||||||
|
|
||||||
add(new JLabel("Genre:"));
|
|
||||||
mGenre = new JTextField();
|
|
||||||
mGenre.getDocument().addDocumentListener(this);
|
|
||||||
mGenre.setToolTipText("Genre (e.g. public safety)");
|
|
||||||
add(mGenre);
|
|
||||||
|
|
||||||
add(new JLabel("Public:"));
|
|
||||||
mPublic = new JCheckBox();
|
|
||||||
mPublic.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mPublic.setToolTipText("Designate stream as public (checked) or private");
|
|
||||||
add(mPublic);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mDelayValue = new JLabel("0 Minutes");
|
|
||||||
add(mDelayValue);
|
|
||||||
|
|
||||||
add(new JLabel("Delay:"));
|
|
||||||
mDelay = new JSlider(0,60,0);
|
|
||||||
mDelay.setMajorTickSpacing(10);
|
|
||||||
mDelay.setMinorTickSpacing(5);
|
|
||||||
mDelay.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
mDelayValue.setText(mDelay.getValue() + " Minutes");
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mDelay.setToolTipText("Audio broadcast delay in minutes");
|
|
||||||
add(mDelay);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mMaximumRecordingAgeValue = new JLabel("1 Minute");
|
|
||||||
add(mMaximumRecordingAgeValue);
|
|
||||||
|
|
||||||
add(new JLabel("Age Limit:"));
|
|
||||||
mMaximumRecordingAge = new JSlider(1,60,5);
|
|
||||||
mMaximumRecordingAge.setMajorTickSpacing(10);
|
|
||||||
mMaximumRecordingAge.setMinorTickSpacing(5);
|
|
||||||
mMaximumRecordingAge.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
int value = mMaximumRecordingAge.getValue();
|
|
||||||
|
|
||||||
mMaximumRecordingAgeValue.setText(value + " Minute" + (value > 1 ? "s" : ""));
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mMaximumRecordingAge.setToolTipText("Maximum recording age (in addition to delay) to stream");
|
|
||||||
add(mMaximumRecordingAge);
|
|
||||||
|
|
||||||
add(new JLabel("Enabled:"));
|
|
||||||
mEnabled = new JCheckBox();
|
|
||||||
mEnabled.setToolTipText("Enable (checked) or disable this stream");
|
|
||||||
mEnabled.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mEnabled);
|
|
||||||
|
|
||||||
mSaveButton = new JButton("Save");
|
|
||||||
mSaveButton.setEnabled(false);
|
|
||||||
mSaveButton.setToolTipText("Click to save configuration information");
|
|
||||||
mSaveButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mSaveButton);
|
|
||||||
|
|
||||||
mResetButton = new JButton("Reset");
|
|
||||||
mResetButton.setEnabled(false);
|
|
||||||
mResetButton.setToolTipText("Click to reset any changes you've made since the last save");
|
|
||||||
mResetButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(false);
|
|
||||||
setItem(getItem());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mResetButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModified(boolean modified)
|
|
||||||
{
|
|
||||||
super.setModified(modified);
|
|
||||||
|
|
||||||
mSaveButton.setEnabled(modified);
|
|
||||||
mResetButton.setEnabled(modified);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(BroadcastConfiguration item)
|
|
||||||
{
|
|
||||||
super.setItem(item);
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
IcecastHTTPConfiguration config = (IcecastHTTPConfiguration)getItem();
|
|
||||||
|
|
||||||
mName.setText(config.getName());
|
|
||||||
mServer.setText(config.getHost());
|
|
||||||
mPort.setText(config.getPort() != 0 ? String.valueOf(config.getPort()) : null);
|
|
||||||
mMountPoint.setText(config.getMountPoint());
|
|
||||||
mUsername.setText(config.getUserName());
|
|
||||||
mPassword.setText(config.getPassword());
|
|
||||||
mDescription.setText(config.getDescription());
|
|
||||||
mGenre.setText(config.getGenre());
|
|
||||||
mPublic.setSelected(config.isPublic());
|
|
||||||
mDelay.setValue((int)(config.getDelay() / ONE_MINUTE_MS));
|
|
||||||
mMaximumRecordingAge.setValue((int)config.getMaximumRecordingAge() / ONE_MINUTE_MS);
|
|
||||||
mEnabled.setSelected(config.isEnabled());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mName.setText(null);
|
|
||||||
mServer.setText(null);
|
|
||||||
mPort.setText(null);
|
|
||||||
mMountPoint.setText(null);
|
|
||||||
mUsername.setText(null);
|
|
||||||
mPassword.setText(null);
|
|
||||||
mDescription.setText(null);
|
|
||||||
mGenre.setText(null);
|
|
||||||
mPublic.setSelected(true);
|
|
||||||
mDelay.setValue(0);
|
|
||||||
mMaximumRecordingAge.setValue(1);
|
|
||||||
mEnabled.setSelected(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
IcecastHTTPConfiguration config = (IcecastHTTPConfiguration)getItem();
|
|
||||||
|
|
||||||
if(validateConfiguration())
|
|
||||||
{
|
|
||||||
updateConfigurationName(config, mName.getText());
|
|
||||||
config.setHost(mServer.getText());
|
|
||||||
config.setPort(getPort());
|
|
||||||
config.setMountPoint(mMountPoint.getText());
|
|
||||||
config.setUserName(mUsername.getText());
|
|
||||||
config.setPassword(mPassword.getText());
|
|
||||||
config.setDescription(mDescription.getText());
|
|
||||||
config.setGenre(mGenre.getText());
|
|
||||||
config.setPublic(mPublic.isSelected());
|
|
||||||
config.setDelay(mDelay.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setMaximumRecordingAge(mMaximumRecordingAge.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setEnabled(mEnabled.isSelected());
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
mBroadcastModel.process(new BroadcastEvent(getItem(), BroadcastEvent.Event.CONFIGURATION_CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the user specified values in the controls prior to saving them to the configuration
|
|
||||||
*/
|
|
||||||
private boolean validateConfiguration()
|
|
||||||
{
|
|
||||||
String name = mName.getText();
|
|
||||||
|
|
||||||
//A unique stream name is required
|
|
||||||
if(!mBroadcastModel.isUniqueName(name, getItem()))
|
|
||||||
{
|
|
||||||
String message = (name == null || name.isEmpty()) ?
|
|
||||||
"Please specify a stream name." : "Stream name " + name +
|
|
||||||
"is already in use.\nPlease choose another name.";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(IcecastHTTPConfigurationEditor.this,
|
|
||||||
message, "Invalid Stream Name", JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
mName.requestFocus();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Server address is optional, but required
|
|
||||||
if(!validateTextField(mServer, "Invalid Server Address", "Please specify a server address."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port is optional, but required
|
|
||||||
if(!validateIntegerTextField(mPort, "Invalid Port Number", "Please specify a port number (1 <> 65535)", 1, 65535))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Mount Point is required
|
|
||||||
if(!validateTextField(mMountPoint, "Invalid Mount Point", "Please specify a mount point."))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//User name is required
|
|
||||||
if(!validateTextField(mUsername, "Invalid User Name", "Please specify a user name."))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Password is required
|
|
||||||
if(!validateTextField(mPassword, "Invalid Password", "Please specify a password."))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an Integer from the port text control or returns 0 if the control doesn't contain an integer value.
|
|
||||||
*/
|
|
||||||
private int getPort()
|
|
||||||
{
|
|
||||||
String port = mPort.getText();
|
|
||||||
|
|
||||||
if(port != null && !port.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(port);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,367 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* 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 <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast.icecast;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastEvent;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JSlider;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class IcecastTCPConfigurationEditor extends BroadcastConfigurationEditor
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger( IcecastTCPConfigurationEditor.class );
|
|
||||||
|
|
||||||
private static final int ONE_MINUTE_MS = 60000;
|
|
||||||
|
|
||||||
private JTextField mName;
|
|
||||||
private JTextField mServer;
|
|
||||||
private JTextField mPort;
|
|
||||||
private JTextField mMountPoint;
|
|
||||||
private JTextField mPassword;
|
|
||||||
private JTextField mDescription;
|
|
||||||
private JTextField mGenre;
|
|
||||||
private JCheckBox mPublic;
|
|
||||||
private JSlider mDelay;
|
|
||||||
private JLabel mDelayValue;
|
|
||||||
private JSlider mMaximumRecordingAge;
|
|
||||||
private JLabel mMaximumRecordingAgeValue;
|
|
||||||
private JCheckBox mEnabled;
|
|
||||||
private JButton mSaveButton;
|
|
||||||
private JButton mResetButton;
|
|
||||||
|
|
||||||
public IcecastTCPConfigurationEditor(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
super(broadcastModel, aliasModel, iconManager);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout( new MigLayout( "fill,wrap 2", "[align right][grow,fill]",
|
|
||||||
"[][][][][][][][][][][][][][][][grow,fill]" ) );
|
|
||||||
setPreferredSize(new Dimension(150,400));
|
|
||||||
|
|
||||||
JLabel channelLabel = new JLabel("Icecast (v2.3) Stream");
|
|
||||||
|
|
||||||
ImageIcon icon = mIconManager.getScaledIcon(BroadcastServerType.ICECAST_TCP.getIconPath(), 25);
|
|
||||||
channelLabel.setIcon(icon);
|
|
||||||
|
|
||||||
add(channelLabel, "span, align center");
|
|
||||||
|
|
||||||
add(new JLabel("Name:"));
|
|
||||||
mName = new JTextField();
|
|
||||||
mName.getDocument().addDocumentListener(this);
|
|
||||||
mName.setToolTipText("Unique name for this stream");
|
|
||||||
add(mName);
|
|
||||||
|
|
||||||
add(new JLabel("Server:"));
|
|
||||||
mServer = new JTextField();
|
|
||||||
mServer.getDocument().addDocumentListener(this);
|
|
||||||
mServer.setToolTipText("Server address (e.g. audio1.icecast.com or localhost)");
|
|
||||||
add(mServer);
|
|
||||||
|
|
||||||
add(new JLabel("Port:"));
|
|
||||||
mPort = new JTextField();
|
|
||||||
mPort.getDocument().addDocumentListener(this);
|
|
||||||
mPort.setToolTipText("Server port number (e.g. 80)");
|
|
||||||
add(mPort);
|
|
||||||
|
|
||||||
add(new JLabel("Mount:"));
|
|
||||||
mMountPoint = new JTextField();
|
|
||||||
mMountPoint.getDocument().addDocumentListener(this);
|
|
||||||
mMountPoint.setToolTipText("Mount point (e.g. /12345)");
|
|
||||||
add(mMountPoint);
|
|
||||||
|
|
||||||
add(new JLabel("Password:"));
|
|
||||||
mPassword = new JTextField();
|
|
||||||
mPassword.getDocument().addDocumentListener(this);
|
|
||||||
mPassword.setToolTipText("Password for the stream");
|
|
||||||
add(mPassword);
|
|
||||||
|
|
||||||
add(new JLabel("Description:"));
|
|
||||||
mDescription = new JTextField();
|
|
||||||
mDescription.getDocument().addDocumentListener(this);
|
|
||||||
mDescription.setToolTipText("Description of the stream contents");
|
|
||||||
add(mDescription);
|
|
||||||
|
|
||||||
add(new JLabel("Genre:"));
|
|
||||||
mGenre = new JTextField();
|
|
||||||
mGenre.getDocument().addDocumentListener(this);
|
|
||||||
mGenre.setToolTipText("Genre (e.g. public safety)");
|
|
||||||
add(mGenre);
|
|
||||||
|
|
||||||
add(new JLabel("Public:"));
|
|
||||||
mPublic = new JCheckBox();
|
|
||||||
mPublic.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mPublic.setToolTipText("Designate stream as public (checked) or private");
|
|
||||||
add(mPublic);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mDelayValue = new JLabel("0 Minutes");
|
|
||||||
add(mDelayValue);
|
|
||||||
|
|
||||||
add(new JLabel("Delay:"));
|
|
||||||
mDelay = new JSlider(0,60,0);
|
|
||||||
mDelay.setMajorTickSpacing(10);
|
|
||||||
mDelay.setMinorTickSpacing(5);
|
|
||||||
mDelay.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
mDelayValue.setText(mDelay.getValue() + " Minutes");
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mDelay.setToolTipText("Audio broadcast delay in minutes");
|
|
||||||
add(mDelay);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mMaximumRecordingAgeValue = new JLabel("1 Minute");
|
|
||||||
add(mMaximumRecordingAgeValue);
|
|
||||||
|
|
||||||
add(new JLabel("Age Limit:"));
|
|
||||||
mMaximumRecordingAge = new JSlider(1,60,5);
|
|
||||||
mMaximumRecordingAge.setMajorTickSpacing(10);
|
|
||||||
mMaximumRecordingAge.setMinorTickSpacing(5);
|
|
||||||
mMaximumRecordingAge.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
int value = mMaximumRecordingAge.getValue();
|
|
||||||
|
|
||||||
mMaximumRecordingAgeValue.setText(value + " Minute" + (value > 1 ? "s" : ""));
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mMaximumRecordingAge.setToolTipText("Maximum recording age (in addition to delay) to stream");
|
|
||||||
add(mMaximumRecordingAge);
|
|
||||||
|
|
||||||
add(new JLabel("Enabled:")); //Empty
|
|
||||||
mEnabled = new JCheckBox();
|
|
||||||
mEnabled.setToolTipText("Enable (checked) or disable this stream");
|
|
||||||
mEnabled.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mEnabled);
|
|
||||||
|
|
||||||
mSaveButton = new JButton("Save");
|
|
||||||
mSaveButton.setEnabled(false);
|
|
||||||
mSaveButton.setToolTipText("Click to save configuration information");
|
|
||||||
mSaveButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mSaveButton);
|
|
||||||
|
|
||||||
mResetButton = new JButton("Reset");
|
|
||||||
mResetButton.setEnabled(false);
|
|
||||||
mResetButton.setToolTipText("Click to reset any changes you've made since the last save");
|
|
||||||
mResetButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(false);
|
|
||||||
setItem(getItem());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mResetButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModified(boolean modified)
|
|
||||||
{
|
|
||||||
super.setModified(modified);
|
|
||||||
|
|
||||||
mSaveButton.setEnabled(modified);
|
|
||||||
mResetButton.setEnabled(modified);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(BroadcastConfiguration item)
|
|
||||||
{
|
|
||||||
super.setItem(item);
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
IcecastTCPConfiguration config = (IcecastTCPConfiguration)getItem();
|
|
||||||
|
|
||||||
mName.setText(config.getName());
|
|
||||||
mServer.setText(config.getHost());
|
|
||||||
mPort.setText(config.getPort() != 0 ? String.valueOf(config.getPort()) : null);
|
|
||||||
mMountPoint.setText(config.getMountPoint());
|
|
||||||
mPassword.setText(config.getPassword());
|
|
||||||
mDescription.setText(config.getDescription());
|
|
||||||
mGenre.setText(config.getGenre());
|
|
||||||
mPublic.setSelected(config.isPublic());
|
|
||||||
mDelay.setValue((int)(config.getDelay() / ONE_MINUTE_MS));
|
|
||||||
mMaximumRecordingAge.setValue((int)config.getMaximumRecordingAge() / ONE_MINUTE_MS);
|
|
||||||
mEnabled.setSelected(config.isEnabled());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mName.setText(null);
|
|
||||||
mServer.setText(null);
|
|
||||||
mPort.setText(null);
|
|
||||||
mMountPoint.setText(null);
|
|
||||||
mPassword.setText(null);
|
|
||||||
mDescription.setText(null);
|
|
||||||
mGenre.setText(null);
|
|
||||||
mPublic.setSelected(true);
|
|
||||||
mDelay.setValue(0);
|
|
||||||
mMaximumRecordingAge.setValue(1);
|
|
||||||
mEnabled.setSelected(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
IcecastTCPConfiguration config = (IcecastTCPConfiguration)getItem();
|
|
||||||
|
|
||||||
if(validateConfiguration())
|
|
||||||
{
|
|
||||||
updateConfigurationName(config, mName.getText());
|
|
||||||
config.setHost(mServer.getText());
|
|
||||||
config.setPort(getPort());
|
|
||||||
config.setMountPoint(mMountPoint.getText());
|
|
||||||
config.setPassword(mPassword.getText());
|
|
||||||
config.setDescription(mDescription.getText());
|
|
||||||
config.setGenre(mGenre.getText());
|
|
||||||
config.setPublic(mPublic.isSelected());
|
|
||||||
config.setDelay(mDelay.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setMaximumRecordingAge(mMaximumRecordingAge.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setEnabled(mEnabled.isSelected());
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
mBroadcastModel.process(new BroadcastEvent(getItem(), BroadcastEvent.Event.CONFIGURATION_CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the user specified values in the controls prior to saving them to the configuration
|
|
||||||
*/
|
|
||||||
private boolean validateConfiguration()
|
|
||||||
{
|
|
||||||
String name = mName.getText();
|
|
||||||
|
|
||||||
//A unique stream name is required
|
|
||||||
if(!mBroadcastModel.isUniqueName(name, getItem()))
|
|
||||||
{
|
|
||||||
String message = (name == null || name.isEmpty()) ?
|
|
||||||
"Please specify a stream name." : "Stream name " + name +
|
|
||||||
"is already in use.\nPlease choose another name.";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(IcecastTCPConfigurationEditor.this,
|
|
||||||
message, "Invalid Stream Name", JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
mName.requestFocus();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Server address is optional, but required
|
|
||||||
if(!validateTextField(mServer, "Invalid Server Address", "Please specify a server address."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port is optional, but required
|
|
||||||
if(!validateIntegerTextField(mPort, "Invalid Port Number", "Please specify a port number (1 <> 65535)", 1, 65535))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Mount Point is optional, but required
|
|
||||||
if(!validateTextField(mMountPoint, "Invalid Mount Point", "Please specify a mount point."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Password is optional, but required
|
|
||||||
if(!validateTextField(mPassword, "Invalid Password", "Please specify a password."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an Integer from the port text control or returns 0 if the control doesn't contain an integer value.
|
|
||||||
*/
|
|
||||||
private int getPort()
|
|
||||||
{
|
|
||||||
String port = mPort.getText();
|
|
||||||
|
|
||||||
if(port != null && !port.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(port);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,351 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* 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 <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast.shoutcast.v1;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastEvent;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JSlider;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class ShoutcastV1ConfigurationEditor extends BroadcastConfigurationEditor
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(ShoutcastV1ConfigurationEditor.class);
|
|
||||||
|
|
||||||
private static final int ONE_MINUTE_MS = 60000;
|
|
||||||
|
|
||||||
private JTextField mName;
|
|
||||||
private JTextField mServer;
|
|
||||||
private JTextField mPort;
|
|
||||||
private JTextField mPassword;
|
|
||||||
private JTextField mGenre;
|
|
||||||
private JTextField mDescription;
|
|
||||||
private JCheckBox mPublic;
|
|
||||||
private JSlider mDelay;
|
|
||||||
private JLabel mDelayValue;
|
|
||||||
private JSlider mMaximumRecordingAge;
|
|
||||||
private JLabel mMaximumRecordingAgeValue;
|
|
||||||
private JCheckBox mEnabled;
|
|
||||||
private JButton mSaveButton;
|
|
||||||
private JButton mResetButton;
|
|
||||||
|
|
||||||
public ShoutcastV1ConfigurationEditor(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
super(broadcastModel, aliasModel, iconManager);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[align right][grow,fill]",
|
|
||||||
"[][][][][][][][][][][][][][][][grow,fill]"));
|
|
||||||
setPreferredSize(new Dimension(150, 400));
|
|
||||||
|
|
||||||
JLabel channelLabel = new JLabel("Shoutcast (v1.x) Stream");
|
|
||||||
|
|
||||||
ImageIcon icon = mIconManager.getScaledIcon(BroadcastServerType.SHOUTCAST_V1.getIconPath(), 25);
|
|
||||||
channelLabel.setIcon(icon);
|
|
||||||
|
|
||||||
add(channelLabel, "span, align center");
|
|
||||||
|
|
||||||
add(new JLabel("Name:"));
|
|
||||||
mName = new JTextField();
|
|
||||||
mName.getDocument().addDocumentListener(this);
|
|
||||||
mName.setToolTipText("Unique name for this stream");
|
|
||||||
add(mName);
|
|
||||||
|
|
||||||
add(new JLabel("Server:"));
|
|
||||||
mServer = new JTextField();
|
|
||||||
mServer.getDocument().addDocumentListener(this);
|
|
||||||
mServer.setToolTipText("Server address (e.g. audio1.shoutcast.com or localhost)");
|
|
||||||
add(mServer);
|
|
||||||
|
|
||||||
add(new JLabel("Port:"));
|
|
||||||
mPort = new JTextField();
|
|
||||||
mPort.getDocument().addDocumentListener(this);
|
|
||||||
mPort.setToolTipText("Server port number (e.g. 80)");
|
|
||||||
add(mPort);
|
|
||||||
|
|
||||||
add(new JLabel("Password:"));
|
|
||||||
mPassword = new JTextField();
|
|
||||||
mPassword.getDocument().addDocumentListener(this);
|
|
||||||
mPassword.setToolTipText("Password for the stream");
|
|
||||||
add(mPassword);
|
|
||||||
|
|
||||||
add(new JLabel("Genre:"));
|
|
||||||
mGenre = new JTextField();
|
|
||||||
mGenre.getDocument().addDocumentListener(this);
|
|
||||||
mGenre.setToolTipText("Genre (e.g. public safety)");
|
|
||||||
add(mGenre);
|
|
||||||
|
|
||||||
add(new JLabel("Description:"));
|
|
||||||
mDescription = new JTextField();
|
|
||||||
mDescription.getDocument().addDocumentListener(this);
|
|
||||||
mDescription.setToolTipText("Description of the stream");
|
|
||||||
add(mDescription);
|
|
||||||
|
|
||||||
add(new JLabel("Public:"));
|
|
||||||
mPublic = new JCheckBox();
|
|
||||||
mPublic.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mPublic.setToolTipText("Designate stream as public (checked) or private");
|
|
||||||
add(mPublic);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mDelayValue = new JLabel("0 Minutes");
|
|
||||||
add(mDelayValue);
|
|
||||||
|
|
||||||
add(new JLabel("Delay:"));
|
|
||||||
mDelay = new JSlider(0, 60, 0);
|
|
||||||
mDelay.setMajorTickSpacing(10);
|
|
||||||
mDelay.setMinorTickSpacing(5);
|
|
||||||
mDelay.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
mDelayValue.setText(mDelay.getValue() + " Minutes");
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mDelay.setToolTipText("Audio broadcast delay in minutes");
|
|
||||||
add(mDelay);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mMaximumRecordingAgeValue = new JLabel("1 Minute");
|
|
||||||
add(mMaximumRecordingAgeValue);
|
|
||||||
|
|
||||||
add(new JLabel("Age Limit:"));
|
|
||||||
mMaximumRecordingAge = new JSlider(1,60,5);
|
|
||||||
mMaximumRecordingAge.setMajorTickSpacing(10);
|
|
||||||
mMaximumRecordingAge.setMinorTickSpacing(5);
|
|
||||||
mMaximumRecordingAge.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
int value = mMaximumRecordingAge.getValue();
|
|
||||||
|
|
||||||
mMaximumRecordingAgeValue.setText(value + " Minute" + (value > 1 ? "s" : ""));
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mMaximumRecordingAge.setToolTipText("Maximum recording age (in addition to delay) to stream");
|
|
||||||
add(mMaximumRecordingAge);
|
|
||||||
|
|
||||||
add(new JLabel("Enabled:")); //Empty
|
|
||||||
mEnabled = new JCheckBox();
|
|
||||||
mEnabled.setToolTipText("Enable (checked) or disable this stream");
|
|
||||||
mEnabled.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mEnabled);
|
|
||||||
|
|
||||||
mSaveButton = new JButton("Save");
|
|
||||||
mSaveButton.setEnabled(false);
|
|
||||||
mSaveButton.setToolTipText("Click to save configuration information");
|
|
||||||
mSaveButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mSaveButton);
|
|
||||||
|
|
||||||
mResetButton = new JButton("Reset");
|
|
||||||
mResetButton.setEnabled(false);
|
|
||||||
mResetButton.setToolTipText("Click to reset any changes you've made since the last save");
|
|
||||||
mResetButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(false);
|
|
||||||
setItem(getItem());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mResetButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModified(boolean modified)
|
|
||||||
{
|
|
||||||
super.setModified(modified);
|
|
||||||
|
|
||||||
mSaveButton.setEnabled(modified);
|
|
||||||
mResetButton.setEnabled(modified);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(BroadcastConfiguration item)
|
|
||||||
{
|
|
||||||
super.setItem(item);
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
ShoutcastV1Configuration config = (ShoutcastV1Configuration) getItem();
|
|
||||||
|
|
||||||
mName.setText(config.getName());
|
|
||||||
mServer.setText(config.getHost());
|
|
||||||
mPort.setText(config.getPort() != 0 ? String.valueOf(config.getPort()) : null);
|
|
||||||
mPassword.setText(config.getPassword());
|
|
||||||
mGenre.setText(config.getGenre());
|
|
||||||
mDescription.setText(config.getDescription());
|
|
||||||
mPublic.setSelected(config.isPublic());
|
|
||||||
mDelay.setValue((int) (config.getDelay() / ONE_MINUTE_MS));
|
|
||||||
mMaximumRecordingAge.setValue((int)config.getMaximumRecordingAge() / ONE_MINUTE_MS);
|
|
||||||
mEnabled.setSelected(config.isEnabled());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mName.setText(null);
|
|
||||||
mServer.setText(null);
|
|
||||||
mPort.setText(null);
|
|
||||||
mPassword.setText(null);
|
|
||||||
mGenre.setText(null);
|
|
||||||
mDescription.setText(null);
|
|
||||||
mPublic.setSelected(true);
|
|
||||||
mDelay.setValue(0);
|
|
||||||
mMaximumRecordingAge.setValue(1);
|
|
||||||
mEnabled.setSelected(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
ShoutcastV1Configuration config = (ShoutcastV1Configuration) getItem();
|
|
||||||
|
|
||||||
if(validateConfiguration())
|
|
||||||
{
|
|
||||||
updateConfigurationName(config, mName.getText());
|
|
||||||
config.setHost(mServer.getText());
|
|
||||||
config.setPort(getPort());
|
|
||||||
config.setPassword(mPassword.getText());
|
|
||||||
config.setDescription(mDescription.getText());
|
|
||||||
config.setGenre(mGenre.getText());
|
|
||||||
config.setPublic(mPublic.isSelected());
|
|
||||||
config.setDelay(mDelay.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setMaximumRecordingAge(mMaximumRecordingAge.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setEnabled(mEnabled.isSelected());
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
mBroadcastModel.process(new BroadcastEvent(getItem(), BroadcastEvent.Event.CONFIGURATION_CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the user specified values in the controls prior to saving them to the configuration
|
|
||||||
*/
|
|
||||||
private boolean validateConfiguration()
|
|
||||||
{
|
|
||||||
String name = mName.getText();
|
|
||||||
|
|
||||||
//A unique stream name is required
|
|
||||||
if(!mBroadcastModel.isUniqueName(name, getItem()))
|
|
||||||
{
|
|
||||||
String message = (name == null || name.isEmpty()) ?
|
|
||||||
"Please specify a stream name." : "Stream name " + name +
|
|
||||||
"is already in use.\nPlease choose another name.";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(ShoutcastV1ConfigurationEditor.this,
|
|
||||||
message, "Invalid Stream Name", JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
mName.requestFocus();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Server address is optional, but required
|
|
||||||
if(!validateTextField(mServer, "Invalid Server Address", "Please specify a server address."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port is optional, but required
|
|
||||||
if(!validateIntegerTextField(mPort, "Invalid Port Number", "Please specify a port number (1 <> 65535)", 1, 65535))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Password is optional, but required
|
|
||||||
if(!validateTextField(mPassword, "Invalid Password", "Please specify a password."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an Integer from the port text control or returns 0 if the control doesn't contain an integer value.
|
|
||||||
*/
|
|
||||||
private int getPort()
|
|
||||||
{
|
|
||||||
String port = mPort.getText();
|
|
||||||
|
|
||||||
if(port != null && !port.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(port);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +1,30 @@
|
|||||||
/*******************************************************************************
|
/*
|
||||||
* sdrtrunk
|
|
||||||
* 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
*/
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast.shoutcast.v2;
|
package io.github.dsheirer.audio.broadcast.shoutcast.v2;
|
||||||
|
|
||||||
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastFormat;
|
import io.github.dsheirer.audio.broadcast.BroadcastFormat;
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
|
|
||||||
public class ShoutcastV2Configuration extends BroadcastConfiguration
|
public class ShoutcastV2Configuration extends BroadcastConfiguration
|
||||||
{
|
{
|
||||||
@@ -90,7 +92,6 @@ public class ShoutcastV2Configuration extends BroadcastConfiguration
|
|||||||
*/
|
*/
|
||||||
public void setStreamID(int streamID)
|
public void setStreamID(int streamID)
|
||||||
{
|
{
|
||||||
Validate.isTrue(1 <= streamID && streamID <= Integer.MAX_VALUE);
|
|
||||||
mStreamID = streamID;
|
mStreamID = streamID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,395 +0,0 @@
|
|||||||
/*******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2017 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.audio.broadcast.shoutcast.v2;
|
|
||||||
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastConfigurationEditor;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastEvent;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
import javax.swing.ImageIcon;
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JCheckBox;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JSlider;
|
|
||||||
import javax.swing.JTextField;
|
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class ShoutcastV2ConfigurationEditor extends BroadcastConfigurationEditor
|
|
||||||
{
|
|
||||||
private final static Logger mLog = LoggerFactory.getLogger(ShoutcastV2ConfigurationEditor.class);
|
|
||||||
|
|
||||||
private static final int ONE_MINUTE_MS = 60000;
|
|
||||||
|
|
||||||
private JTextField mName;
|
|
||||||
private JTextField mServer;
|
|
||||||
private JTextField mPort;
|
|
||||||
private JTextField mStreamID;
|
|
||||||
private JTextField mUserID;
|
|
||||||
private JTextField mPassword;
|
|
||||||
private JTextField mGenre;
|
|
||||||
private JCheckBox mPublic;
|
|
||||||
private JSlider mDelay;
|
|
||||||
private JLabel mDelayValue;
|
|
||||||
private JSlider mMaximumRecordingAge;
|
|
||||||
private JLabel mMaximumRecordingAgeValue;
|
|
||||||
private JCheckBox mEnabled;
|
|
||||||
private JButton mSaveButton;
|
|
||||||
private JButton mResetButton;
|
|
||||||
|
|
||||||
public ShoutcastV2ConfigurationEditor(BroadcastModel broadcastModel, AliasModel aliasModel, IconManager iconManager)
|
|
||||||
{
|
|
||||||
super(broadcastModel, aliasModel, iconManager);
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 2", "[align right][grow,fill]",
|
|
||||||
"[][][][][][][][][][][][][][][][grow,fill]"));
|
|
||||||
setPreferredSize(new Dimension(150, 400));
|
|
||||||
|
|
||||||
JLabel channelLabel = new JLabel("Shoutcast (v2) Stream");
|
|
||||||
|
|
||||||
ImageIcon icon = mIconManager.getScaledIcon(BroadcastServerType.SHOUTCAST_V2.getIconPath(), 25);
|
|
||||||
channelLabel.setIcon(icon);
|
|
||||||
|
|
||||||
add(channelLabel, "span, align center");
|
|
||||||
|
|
||||||
add(new JLabel("Name:"));
|
|
||||||
mName = new JTextField();
|
|
||||||
mName.getDocument().addDocumentListener(this);
|
|
||||||
mName.setToolTipText("Unique name for this stream");
|
|
||||||
add(mName);
|
|
||||||
|
|
||||||
add(new JLabel("Server:"));
|
|
||||||
mServer = new JTextField();
|
|
||||||
mServer.getDocument().addDocumentListener(this);
|
|
||||||
mServer.setToolTipText("Server address (e.g. audio1.shoutcast.com or localhost)");
|
|
||||||
add(mServer);
|
|
||||||
|
|
||||||
add(new JLabel("Port:"));
|
|
||||||
mPort = new JTextField();
|
|
||||||
mPort.getDocument().addDocumentListener(this);
|
|
||||||
mPort.setToolTipText("Server port number (e.g. 80)");
|
|
||||||
add(mPort);
|
|
||||||
|
|
||||||
add(new JLabel("Stream ID:"));
|
|
||||||
mStreamID = new JTextField();
|
|
||||||
mStreamID.getDocument().addDocumentListener(this);
|
|
||||||
mStreamID.setToolTipText("Stream Identifier)");
|
|
||||||
add(mStreamID);
|
|
||||||
|
|
||||||
add(new JLabel("User ID:"));
|
|
||||||
mUserID = new JTextField();
|
|
||||||
mUserID.getDocument().addDocumentListener(this);
|
|
||||||
mUserID.setToolTipText("User ID/Name");
|
|
||||||
add(mUserID);
|
|
||||||
|
|
||||||
add(new JLabel("Password:"));
|
|
||||||
mPassword = new JTextField();
|
|
||||||
mPassword.getDocument().addDocumentListener(this);
|
|
||||||
mPassword.setToolTipText("Password for the stream");
|
|
||||||
add(mPassword);
|
|
||||||
|
|
||||||
add(new JLabel("Genre:"));
|
|
||||||
mGenre = new JTextField();
|
|
||||||
mGenre.getDocument().addDocumentListener(this);
|
|
||||||
mGenre.setToolTipText("Genre (e.g. public safety)");
|
|
||||||
add(mGenre);
|
|
||||||
|
|
||||||
add(new JLabel("Public:"));
|
|
||||||
mPublic = new JCheckBox();
|
|
||||||
mPublic.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mPublic.setToolTipText("Designate stream as public (checked) or private");
|
|
||||||
add(mPublic);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mDelayValue = new JLabel("0 Minutes");
|
|
||||||
add(mDelayValue);
|
|
||||||
|
|
||||||
add(new JLabel("Delay:"));
|
|
||||||
mDelay = new JSlider(0, 60, 0);
|
|
||||||
mDelay.setMajorTickSpacing(10);
|
|
||||||
mDelay.setMinorTickSpacing(5);
|
|
||||||
mDelay.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
mDelayValue.setText(mDelay.getValue() + " Minutes");
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mDelay.setToolTipText("Audio broadcast delay in minutes");
|
|
||||||
add(mDelay);
|
|
||||||
|
|
||||||
add(new JLabel());
|
|
||||||
mMaximumRecordingAgeValue = new JLabel("1 Minute");
|
|
||||||
add(mMaximumRecordingAgeValue);
|
|
||||||
|
|
||||||
add(new JLabel("Age Limit:"));
|
|
||||||
mMaximumRecordingAge = new JSlider(1,60,5);
|
|
||||||
mMaximumRecordingAge.setMajorTickSpacing(10);
|
|
||||||
mMaximumRecordingAge.setMinorTickSpacing(5);
|
|
||||||
mMaximumRecordingAge.addChangeListener(new ChangeListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void stateChanged(ChangeEvent e)
|
|
||||||
{
|
|
||||||
int value = mMaximumRecordingAge.getValue();
|
|
||||||
|
|
||||||
mMaximumRecordingAgeValue.setText(value + " Minute" + (value > 1 ? "s" : ""));
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
mMaximumRecordingAge.setToolTipText("Maximum recording age (in addition to delay) to stream");
|
|
||||||
add(mMaximumRecordingAge);
|
|
||||||
|
|
||||||
add(new JLabel("Enabled:")); //Empty
|
|
||||||
mEnabled = new JCheckBox();
|
|
||||||
mEnabled.setToolTipText("Enable (checked) or disable this stream");
|
|
||||||
mEnabled.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(true);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mEnabled);
|
|
||||||
|
|
||||||
mSaveButton = new JButton("Save");
|
|
||||||
mSaveButton.setEnabled(false);
|
|
||||||
mSaveButton.setToolTipText("Click to save configuration information");
|
|
||||||
mSaveButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mSaveButton);
|
|
||||||
|
|
||||||
mResetButton = new JButton("Reset");
|
|
||||||
mResetButton.setEnabled(false);
|
|
||||||
mResetButton.setToolTipText("Click to reset any changes you've made since the last save");
|
|
||||||
mResetButton.addActionListener(new ActionListener()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
setModified(false);
|
|
||||||
setItem(getItem());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(mResetButton);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setModified(boolean modified)
|
|
||||||
{
|
|
||||||
super.setModified(modified);
|
|
||||||
|
|
||||||
mSaveButton.setEnabled(modified);
|
|
||||||
mResetButton.setEnabled(modified);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setItem(BroadcastConfiguration item)
|
|
||||||
{
|
|
||||||
super.setItem(item);
|
|
||||||
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
ShoutcastV2Configuration config = (ShoutcastV2Configuration) getItem();
|
|
||||||
|
|
||||||
mName.setText(config.getName());
|
|
||||||
mServer.setText(config.getHost());
|
|
||||||
mPort.setText(config.getPort() != 0 ? String.valueOf(config.getPort()) : null);
|
|
||||||
mStreamID.setText(String.valueOf(config.getStreamID()));
|
|
||||||
mUserID.setText(config.getUserID());
|
|
||||||
mPassword.setText(config.getPassword());
|
|
||||||
mGenre.setText(config.getGenre());
|
|
||||||
mPublic.setSelected(config.isPublic());
|
|
||||||
mDelay.setValue((int) (config.getDelay() / ONE_MINUTE_MS));
|
|
||||||
mMaximumRecordingAge.setValue((int)config.getMaximumRecordingAge() / ONE_MINUTE_MS);
|
|
||||||
mEnabled.setSelected(config.isEnabled());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mName.setText(null);
|
|
||||||
mServer.setText(null);
|
|
||||||
mPort.setText(null);
|
|
||||||
mStreamID.setText(null);
|
|
||||||
mUserID.setText(null);
|
|
||||||
mPassword.setText(null);
|
|
||||||
mGenre.setText(null);
|
|
||||||
mPublic.setSelected(true);
|
|
||||||
mDelay.setValue(0);
|
|
||||||
mMaximumRecordingAge.setValue(1);
|
|
||||||
mEnabled.setSelected(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
ShoutcastV2Configuration config = (ShoutcastV2Configuration) getItem();
|
|
||||||
|
|
||||||
if(validateConfiguration())
|
|
||||||
{
|
|
||||||
updateConfigurationName(config, mName.getText());
|
|
||||||
config.setHost(mServer.getText());
|
|
||||||
config.setPort(getPort());
|
|
||||||
config.setUserID(mUserID.getText());
|
|
||||||
config.setPassword(mPassword.getText());
|
|
||||||
config.setStreamID(getStreamID());
|
|
||||||
config.setGenre(mGenre.getText());
|
|
||||||
config.setPublic(mPublic.isSelected());
|
|
||||||
config.setDelay(mDelay.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setMaximumRecordingAge(mMaximumRecordingAge.getValue() * ONE_MINUTE_MS);
|
|
||||||
config.setEnabled(mEnabled.isSelected());
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
mBroadcastModel.process(new BroadcastEvent(getItem(), BroadcastEvent.Event.CONFIGURATION_CHANGE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the user specified values in the controls prior to saving them to the configuration
|
|
||||||
*/
|
|
||||||
private boolean validateConfiguration()
|
|
||||||
{
|
|
||||||
String name = mName.getText();
|
|
||||||
|
|
||||||
//A unique stream name is required
|
|
||||||
if(!mBroadcastModel.isUniqueName(name, getItem()))
|
|
||||||
{
|
|
||||||
String message = (name == null || name.isEmpty()) ?
|
|
||||||
"Please specify a stream name." : "Stream name " + name +
|
|
||||||
"is already in use.\nPlease choose another name.";
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(ShoutcastV2ConfigurationEditor.this,
|
|
||||||
message, "Invalid Stream Name", JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
mName.requestFocus();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Server address is required
|
|
||||||
if(!validateTextField(mServer, "Invalid Server Address", "Please specify a server address."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Port is required
|
|
||||||
if(!validateIntegerTextField(mPort, "Invalid Port Number", "Please specify a port number (1 <> 65535)", 1, 65535))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Stream ID is required
|
|
||||||
if(!validateIntegerTextField(mStreamID, "Invalid Stream ID", "Please specify a stream ID of 1 or higher", 1, Integer.MAX_VALUE))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//User ID is required
|
|
||||||
if(!validateTextField(mUserID, "Invalid User ID", "Please specify a user ID/name."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Password is required
|
|
||||||
if(!validateTextField(mPassword, "Invalid Password", "Please specify a password."))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an Integer from the port text control or returns 0 if the control doesn't contain an integer value.
|
|
||||||
*/
|
|
||||||
private int getPort()
|
|
||||||
{
|
|
||||||
String port = mPort.getText();
|
|
||||||
|
|
||||||
if(port != null && !port.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(port);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses an Integer from the port text control or returns 0 if the control doesn't contain an integer value.
|
|
||||||
*/
|
|
||||||
private int getStreamID()
|
|
||||||
{
|
|
||||||
String streamID = mStreamID.getText();
|
|
||||||
|
|
||||||
if(streamID != null && !streamID.isEmpty())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Integer.parseInt(streamID);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
//Do nothing, we couldn't parse the number value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -120,7 +120,7 @@ public class AudioChannelPanel extends JPanel implements Listener<AudioEvent>, S
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void preferenceUpdated(PreferenceType preferenceType)
|
public void preferenceUpdated(PreferenceType preferenceType)
|
||||||
{
|
{
|
||||||
if(preferenceType == PreferenceType.IDENTIFIER)
|
if(preferenceType == PreferenceType.TALKGROUP_FORMAT)
|
||||||
{
|
{
|
||||||
updateLabels();
|
updateLabels();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,14 +25,13 @@ import io.github.dsheirer.audio.AudioException;
|
|||||||
import io.github.dsheirer.audio.IAudioController;
|
import io.github.dsheirer.audio.IAudioController;
|
||||||
import io.github.dsheirer.eventbus.MyEventBus;
|
import io.github.dsheirer.eventbus.MyEventBus;
|
||||||
import io.github.dsheirer.gui.preference.PreferenceEditorType;
|
import io.github.dsheirer.gui.preference.PreferenceEditorType;
|
||||||
import io.github.dsheirer.gui.preference.PreferenceEditorViewRequest;
|
import io.github.dsheirer.gui.preference.UserPreferenceEditorViewRequest;
|
||||||
import io.github.dsheirer.icon.IconManager;
|
import io.github.dsheirer.icon.IconManager;
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
import io.github.dsheirer.preference.UserPreferences;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
import io.github.dsheirer.settings.SettingsManager;
|
import io.github.dsheirer.settings.SettingsManager;
|
||||||
import io.github.dsheirer.source.SourceManager;
|
import io.github.dsheirer.source.SourceManager;
|
||||||
import io.github.dsheirer.source.mixer.MixerChannelConfiguration;
|
import io.github.dsheirer.source.mixer.MixerChannelConfiguration;
|
||||||
import io.github.dsheirer.source.mixer.MixerManager;
|
|
||||||
import jiconfont.icons.font_awesome.FontAwesome;
|
import jiconfont.icons.font_awesome.FontAwesome;
|
||||||
import jiconfont.swing.IconFontSwing;
|
import jiconfont.swing.IconFontSwing;
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
@@ -58,7 +57,6 @@ import java.awt.event.ActionEvent;
|
|||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.MouseListener;
|
import java.awt.event.MouseListener;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AudioPanel extends JPanel implements Listener<AudioEvent>
|
public class AudioPanel extends JPanel implements Listener<AudioEvent>
|
||||||
{
|
{
|
||||||
@@ -185,7 +183,7 @@ public class AudioPanel extends JPanel implements Listener<AudioEvent>
|
|||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e)
|
public void actionPerformed(ActionEvent e)
|
||||||
{
|
{
|
||||||
MyEventBus.getEventBus().post(new PreferenceEditorViewRequest(PreferenceEditorType.AUDIO_PLAYBACK));
|
MyEventBus.getEventBus().post(new UserPreferenceEditorViewRequest(PreferenceEditorType.AUDIO_OUTPUT));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
popup.add(outputMenu);
|
popup.add(outputMenu);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public class ChannelMetadataModel extends AbstractTableModel implements IChannel
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void preferenceUpdated(PreferenceType preferenceType)
|
public void preferenceUpdated(PreferenceType preferenceType)
|
||||||
{
|
{
|
||||||
if(preferenceType == PreferenceType.IDENTIFIER)
|
if(preferenceType == PreferenceType.TALKGROUP_FORMAT)
|
||||||
{
|
{
|
||||||
for(int row = 0; row < mChannelMetadata.size(); row++)
|
for(int row = 0; row < mChannelMetadata.size(); row++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import io.github.dsheirer.identifier.Identifier;
|
|||||||
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier;
|
import io.github.dsheirer.identifier.configuration.FrequencyConfigurationIdentifier;
|
||||||
import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier;
|
import io.github.dsheirer.identifier.decoder.ChannelStateIdentifier;
|
||||||
import io.github.dsheirer.module.ProcessingChain;
|
import io.github.dsheirer.module.ProcessingChain;
|
||||||
|
import io.github.dsheirer.playlist.PlaylistManager;
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
import io.github.dsheirer.preference.UserPreferences;
|
||||||
import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
|
import io.github.dsheirer.preference.identifier.TalkgroupFormatPreference;
|
||||||
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
|
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
|
||||||
@@ -76,11 +77,10 @@ public class ChannelMetadataPanel extends JPanel implements ListSelectionListene
|
|||||||
/**
|
/**
|
||||||
* Table view for currently decoding channel metadata
|
* Table view for currently decoding channel metadata
|
||||||
*/
|
*/
|
||||||
public ChannelMetadataPanel(ChannelModel channelModel, ChannelProcessingManager channelProcessingManager,
|
public ChannelMetadataPanel(PlaylistManager playlistManager, IconManager iconManager, UserPreferences userPreferences)
|
||||||
IconManager iconManager, UserPreferences userPreferences)
|
|
||||||
{
|
{
|
||||||
mChannelModel = channelModel;
|
mChannelModel = playlistManager.getChannelModel();
|
||||||
mChannelProcessingManager = channelProcessingManager;
|
mChannelProcessingManager = playlistManager.getChannelProcessingManager();
|
||||||
mIconManager = iconManager;
|
mIconManager = iconManager;
|
||||||
mUserPreferences = userPreferences;
|
mUserPreferences = userPreferences;
|
||||||
init();
|
init();
|
||||||
|
|||||||
@@ -21,13 +21,11 @@ package io.github.dsheirer.channel.metadata;
|
|||||||
|
|
||||||
import com.jidesoft.swing.JideSplitPane;
|
import com.jidesoft.swing.JideSplitPane;
|
||||||
import com.jidesoft.swing.JideTabbedPane;
|
import com.jidesoft.swing.JideTabbedPane;
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.channel.details.ChannelDetailPanel;
|
import io.github.dsheirer.channel.details.ChannelDetailPanel;
|
||||||
import io.github.dsheirer.controller.channel.ChannelModel;
|
|
||||||
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
import io.github.dsheirer.icon.IconManager;
|
||||||
import io.github.dsheirer.module.decode.event.DecodeEventPanel;
|
import io.github.dsheirer.module.decode.event.DecodeEventPanel;
|
||||||
import io.github.dsheirer.module.decode.event.MessageActivityPanel;
|
import io.github.dsheirer.module.decode.event.MessageActivityPanel;
|
||||||
|
import io.github.dsheirer.playlist.PlaylistManager;
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
import io.github.dsheirer.preference.UserPreferences;
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
|
|
||||||
@@ -45,13 +43,12 @@ public class NowPlayingPanel extends JPanel
|
|||||||
* GUI panel that combines the currently decoding channels metadata table and viewers for channel details,
|
* GUI panel that combines the currently decoding channels metadata table and viewers for channel details,
|
||||||
* messages, events, and spectral view.
|
* messages, events, and spectral view.
|
||||||
*/
|
*/
|
||||||
public NowPlayingPanel(ChannelModel channelModel, ChannelProcessingManager channelProcessingManager,
|
public NowPlayingPanel(PlaylistManager playlistManager, IconManager iconManager, UserPreferences userPreferences)
|
||||||
IconManager iconManager, AliasModel aliasModel, UserPreferences userPreferences)
|
|
||||||
{
|
{
|
||||||
mChannelDetailPanel = new ChannelDetailPanel(channelProcessingManager);
|
mChannelDetailPanel = new ChannelDetailPanel(playlistManager.getChannelProcessingManager());
|
||||||
mDecodeEventPanel = new DecodeEventPanel(iconManager, userPreferences, aliasModel);
|
mDecodeEventPanel = new DecodeEventPanel(iconManager, userPreferences, playlistManager.getAliasModel());
|
||||||
mMessageActivityPanel = new MessageActivityPanel(userPreferences);
|
mMessageActivityPanel = new MessageActivityPanel(userPreferences);
|
||||||
mChannelMetadataPanel = new ChannelMetadataPanel(channelModel, channelProcessingManager, iconManager, userPreferences);
|
mChannelMetadataPanel = new ChannelMetadataPanel(playlistManager, iconManager, userPreferences);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,71 +19,53 @@
|
|||||||
package io.github.dsheirer.controller;
|
package io.github.dsheirer.controller;
|
||||||
|
|
||||||
import com.jidesoft.swing.JideTabbedPane;
|
import com.jidesoft.swing.JideTabbedPane;
|
||||||
import io.github.dsheirer.alias.AliasController;
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastModel;
|
|
||||||
import io.github.dsheirer.audio.broadcast.BroadcastPanel;
|
|
||||||
import io.github.dsheirer.audio.playback.AudioPanel;
|
import io.github.dsheirer.audio.playback.AudioPanel;
|
||||||
import io.github.dsheirer.audio.playback.AudioPlaybackManager;
|
import io.github.dsheirer.audio.playback.AudioPlaybackManager;
|
||||||
import io.github.dsheirer.channel.metadata.NowPlayingPanel;
|
import io.github.dsheirer.channel.metadata.NowPlayingPanel;
|
||||||
import io.github.dsheirer.controller.channel.ChannelController;
|
import io.github.dsheirer.eventbus.MyEventBus;
|
||||||
import io.github.dsheirer.controller.channel.ChannelModel;
|
import io.github.dsheirer.gui.playlist.ViewPlaylistRequest;
|
||||||
import io.github.dsheirer.controller.channel.ChannelProcessingManager;
|
|
||||||
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
|
|
||||||
import io.github.dsheirer.icon.IconManager;
|
import io.github.dsheirer.icon.IconManager;
|
||||||
import io.github.dsheirer.map.MapPanel;
|
import io.github.dsheirer.map.MapPanel;
|
||||||
import io.github.dsheirer.map.MapService;
|
import io.github.dsheirer.map.MapService;
|
||||||
|
import io.github.dsheirer.playlist.PlaylistManager;
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
import io.github.dsheirer.preference.UserPreferences;
|
||||||
import io.github.dsheirer.settings.SettingsManager;
|
import io.github.dsheirer.settings.SettingsManager;
|
||||||
import io.github.dsheirer.source.SourceManager;
|
import io.github.dsheirer.source.SourceManager;
|
||||||
import io.github.dsheirer.source.tuner.TunerModel;
|
|
||||||
import io.github.dsheirer.source.tuner.TunerViewPanel;
|
import io.github.dsheirer.source.tuner.TunerViewPanel;
|
||||||
|
import jiconfont.icons.font_awesome.FontAwesome;
|
||||||
|
import jiconfont.swing.IconFontSwing;
|
||||||
import net.miginfocom.swing.MigLayout;
|
import net.miginfocom.swing.MigLayout;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import javax.swing.Icon;
|
||||||
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
|
||||||
public class ControllerPanel extends JPanel
|
public class ControllerPanel extends JPanel
|
||||||
{
|
{
|
||||||
|
private final static Logger mLog = LoggerFactory.getLogger(ControllerPanel.class);
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
private int mSettingsTabIndex = -1;
|
||||||
|
|
||||||
private AliasController mAliasController;
|
|
||||||
private AudioPanel mAudioPanel;
|
private AudioPanel mAudioPanel;
|
||||||
private BroadcastPanel mBroadcastPanel;
|
|
||||||
private ChannelController mChannelController;
|
|
||||||
private NowPlayingPanel mNowPlayingPanel;
|
private NowPlayingPanel mNowPlayingPanel;
|
||||||
private ChannelModel mChannelModel;
|
|
||||||
private MapPanel mMapPanel;
|
private MapPanel mMapPanel;
|
||||||
private TunerViewPanel mTunerManagerPanel;
|
private TunerViewPanel mTunerManagerPanel;
|
||||||
private BroadcastModel mBroadcastModel;
|
|
||||||
|
|
||||||
private JideTabbedPane mTabbedPane;
|
private JideTabbedPane mTabbedPane;
|
||||||
|
|
||||||
public ControllerPanel(AudioPlaybackManager audioPlaybackManager, AliasModel aliasModel, BroadcastModel broadcastModel,
|
public ControllerPanel(PlaylistManager playlistManager, AudioPlaybackManager audioPlaybackManager,
|
||||||
ChannelModel channelModel, ChannelMapModel channelMapModel, ChannelProcessingManager channelProcessingManager,
|
|
||||||
IconManager iconManager, MapService mapService, SettingsManager settingsManager,
|
IconManager iconManager, MapService mapService, SettingsManager settingsManager,
|
||||||
SourceManager sourceManager, TunerModel tunerModel, UserPreferences userPreferences)
|
SourceManager sourceManager, UserPreferences userPreferences)
|
||||||
{
|
{
|
||||||
mBroadcastModel = broadcastModel;
|
|
||||||
mChannelModel = channelModel;
|
|
||||||
|
|
||||||
mAudioPanel = new AudioPanel(iconManager, userPreferences, settingsManager, sourceManager, audioPlaybackManager,
|
mAudioPanel = new AudioPanel(iconManager, userPreferences, settingsManager, sourceManager, audioPlaybackManager,
|
||||||
aliasModel);
|
playlistManager.getAliasModel());
|
||||||
|
mNowPlayingPanel = new NowPlayingPanel(playlistManager, iconManager, userPreferences);
|
||||||
mNowPlayingPanel = new NowPlayingPanel(channelModel, channelProcessingManager, iconManager,
|
mMapPanel = new MapPanel(mapService, playlistManager.getAliasModel(), iconManager, settingsManager);
|
||||||
aliasModel, userPreferences);
|
mTunerManagerPanel = new TunerViewPanel(sourceManager.getTunerModel(), userPreferences);
|
||||||
|
|
||||||
mMapPanel = new MapPanel(mapService, aliasModel, iconManager, settingsManager);
|
|
||||||
|
|
||||||
mBroadcastPanel = new BroadcastPanel(broadcastModel, aliasModel, iconManager, userPreferences);
|
|
||||||
|
|
||||||
mChannelController = new ChannelController(channelModel, channelProcessingManager, channelMapModel,
|
|
||||||
sourceManager, aliasModel, userPreferences);
|
|
||||||
|
|
||||||
mAliasController = new AliasController(aliasModel, broadcastModel, iconManager, userPreferences);
|
|
||||||
|
|
||||||
mTunerManagerPanel = new TunerViewPanel(tunerModel, userPreferences);
|
|
||||||
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
@@ -94,20 +76,34 @@ public class ControllerPanel extends JPanel
|
|||||||
|
|
||||||
add(mAudioPanel, "wrap");
|
add(mAudioPanel, "wrap");
|
||||||
|
|
||||||
//Tabbed View - configuration, calls, messages, map
|
mTabbedPane = new JideTabbedPane()
|
||||||
mTabbedPane = new JideTabbedPane();
|
{
|
||||||
|
@Override
|
||||||
|
public void setSelectedIndex(int index)
|
||||||
|
{
|
||||||
|
if(index == mSettingsTabIndex)
|
||||||
|
{
|
||||||
|
MyEventBus.getEventBus().post(new ViewPlaylistRequest());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
super.setSelectedIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
mTabbedPane.setFont(this.getFont());
|
mTabbedPane.setFont(this.getFont());
|
||||||
mTabbedPane.setForeground(Color.BLACK);
|
mTabbedPane.setForeground(Color.BLACK);
|
||||||
mTabbedPane.addTab("Now Playing", mNowPlayingPanel);
|
mTabbedPane.addTab("Now Playing", mNowPlayingPanel);
|
||||||
mTabbedPane.addTab("Aliases", mAliasController);
|
|
||||||
mTabbedPane.addTab("Channels", mChannelController);
|
|
||||||
mTabbedPane.addTab("Map", mMapPanel);
|
mTabbedPane.addTab("Map", mMapPanel);
|
||||||
mTabbedPane.addTab("Streaming", mBroadcastPanel);
|
|
||||||
mTabbedPane.addTab("Tuners", mTunerManagerPanel);
|
mTabbedPane.addTab("Tuners", mTunerManagerPanel);
|
||||||
|
|
||||||
|
Icon gearIcon = IconFontSwing.buildIcon(FontAwesome.COG, 20, Color.DARK_GRAY);
|
||||||
|
mTabbedPane.addTab("Playlist Editor", gearIcon, new JLabel("Show Playlist Manager"));
|
||||||
|
mSettingsTabIndex = mTabbedPane.getTabCount() - 1;
|
||||||
|
|
||||||
//Set preferred size to influence the split between these panels
|
//Set preferred size to influence the split between these panels
|
||||||
mTabbedPane.setPreferredSize(new Dimension(880, 500));
|
mTabbedPane.setPreferredSize(new Dimension(880, 500));
|
||||||
|
|
||||||
add(mTabbedPane,"wrap");
|
add(mTabbedPane, "wrap");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,23 @@
|
|||||||
/*
|
/*
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
*/
|
||||||
package io.github.dsheirer.controller.channel;
|
package io.github.dsheirer.controller.channel;
|
||||||
|
|
||||||
@@ -39,6 +41,14 @@ import io.github.dsheirer.source.config.SourceConfigRecording;
|
|||||||
import io.github.dsheirer.source.config.SourceConfigTuner;
|
import io.github.dsheirer.source.config.SourceConfigTuner;
|
||||||
import io.github.dsheirer.source.config.SourceConfiguration;
|
import io.github.dsheirer.source.config.SourceConfiguration;
|
||||||
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
import io.github.dsheirer.source.tuner.channel.TunerChannel;
|
||||||
|
import javafx.beans.Observable;
|
||||||
|
import javafx.beans.property.BooleanProperty;
|
||||||
|
import javafx.beans.property.IntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleBooleanProperty;
|
||||||
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.util.Callback;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -64,14 +74,14 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
private EventLogConfiguration mEventLogConfiguration = new EventLogConfiguration();
|
private EventLogConfiguration mEventLogConfiguration = new EventLogConfiguration();
|
||||||
private RecordConfiguration mRecordConfiguration = new RecordConfiguration();
|
private RecordConfiguration mRecordConfiguration = new RecordConfiguration();
|
||||||
|
|
||||||
private String mAliasListName;
|
private StringProperty mAliasListName = new SimpleStringProperty();
|
||||||
private String mSystem = "System";
|
private StringProperty mSystem = new SimpleStringProperty();
|
||||||
private String mSite = "Site";
|
private StringProperty mSite = new SimpleStringProperty();
|
||||||
private String mName = "Channel";
|
private StringProperty mName = new SimpleStringProperty();
|
||||||
|
|
||||||
private boolean mProcessing;
|
private BooleanProperty mProcessing = new SimpleBooleanProperty();
|
||||||
private boolean mAutoStart;
|
private BooleanProperty mAutoStart = new SimpleBooleanProperty();
|
||||||
private Integer mAutoStartOrder;
|
private IntegerProperty mAutoStartOrder = new SimpleIntegerProperty();
|
||||||
private boolean mSelected;
|
private boolean mSelected;
|
||||||
private TunerChannel mTunerChannel = null;
|
private TunerChannel mTunerChannel = null;
|
||||||
|
|
||||||
@@ -100,7 +110,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
public Channel(String channelName)
|
public Channel(String channelName)
|
||||||
{
|
{
|
||||||
this();
|
this();
|
||||||
mName = channelName;
|
mName.set(channelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -111,52 +121,119 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
mChannelID = UNIQUE_ID++;
|
mChannelID = UNIQUE_ID++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a (new) deep copy of this channel
|
* Creates a (new) deep copy of this channel
|
||||||
*/
|
*/
|
||||||
public Channel copyOf()
|
public Channel copyOf()
|
||||||
{
|
{
|
||||||
Channel channel = new Channel(mName);
|
Channel channel = new Channel(mName.get());
|
||||||
channel.setSystem(mSystem);
|
channel.setSystem(mSystem.get());
|
||||||
channel.setSite(mSite);
|
channel.setSite(mSite.get());
|
||||||
channel.setAliasListName(mAliasListName);
|
channel.setAliasListName(mAliasListName.get());
|
||||||
channel.setAutoStart(mAutoStart);
|
channel.setAutoStart(mAutoStart.get());
|
||||||
channel.setAutoStartOrder(mAutoStartOrder);
|
channel.setAutoStartOrder(mAutoStartOrder.get());
|
||||||
|
|
||||||
AuxDecodeConfiguration aux = new AuxDecodeConfiguration();
|
AuxDecodeConfiguration auxCopy = new AuxDecodeConfiguration();
|
||||||
|
|
||||||
for(DecoderType auxType : aux.getAuxDecoders())
|
if(getAuxDecodeConfiguration() != null)
|
||||||
{
|
{
|
||||||
aux.addAuxDecoder(auxType);
|
for(DecoderType auxType : getAuxDecodeConfiguration().getAuxDecoders())
|
||||||
|
{
|
||||||
|
auxCopy.addAuxDecoder(auxType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.setAuxDecodeConfiguration(aux);
|
channel.setAuxDecodeConfiguration(auxCopy);
|
||||||
|
|
||||||
channel.setDecodeConfiguration(DecoderFactory.copy(mDecodeConfiguration));
|
channel.setDecodeConfiguration(DecoderFactory.copy(mDecodeConfiguration));
|
||||||
|
|
||||||
EventLogConfiguration log = new EventLogConfiguration();
|
EventLogConfiguration logCopy = new EventLogConfiguration();
|
||||||
|
|
||||||
for(EventLogType logType : mEventLogConfiguration.getLoggers())
|
if(mEventLogConfiguration != null)
|
||||||
{
|
{
|
||||||
log.addLogger(logType);
|
for(EventLogType logType : mEventLogConfiguration.getLoggers())
|
||||||
|
{
|
||||||
|
logCopy.addLogger(logType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.setEventLogConfiguration(log);
|
channel.setEventLogConfiguration(logCopy);
|
||||||
|
|
||||||
RecordConfiguration record = new RecordConfiguration();
|
RecordConfiguration recordCopy = new RecordConfiguration();
|
||||||
|
|
||||||
for(RecorderType recordType : mRecordConfiguration.getRecorders())
|
if(mRecordConfiguration != null)
|
||||||
{
|
{
|
||||||
record.addRecorder(recordType);
|
for(RecorderType recordType : mRecordConfiguration.getRecorders())
|
||||||
|
{
|
||||||
|
recordCopy.addRecorder(recordType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
channel.setRecordConfiguration(record);
|
channel.setRecordConfiguration(recordCopy);
|
||||||
|
|
||||||
channel.setSourceConfiguration(SourceConfigFactory.copy(mSourceConfiguration));
|
channel.setSourceConfiguration(SourceConfigFactory.copy(mSourceConfiguration));
|
||||||
|
|
||||||
return channel;
|
return channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias list name property
|
||||||
|
*/
|
||||||
|
public StringProperty aliasListNameProperty()
|
||||||
|
{
|
||||||
|
return mAliasListName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System property
|
||||||
|
*/
|
||||||
|
public StringProperty systemProperty()
|
||||||
|
{
|
||||||
|
return mSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Site property
|
||||||
|
*/
|
||||||
|
public StringProperty siteProperty()
|
||||||
|
{
|
||||||
|
return mSite;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Channel name property
|
||||||
|
*/
|
||||||
|
public StringProperty nameProperty()
|
||||||
|
{
|
||||||
|
return mName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processing property. Indicates if this channel configuration is currently processing.
|
||||||
|
*/
|
||||||
|
public BooleanProperty processingProperty()
|
||||||
|
{
|
||||||
|
return mProcessing;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-Start property. Indicates if this channel is setup for auto-start
|
||||||
|
*/
|
||||||
|
public BooleanProperty autoStartProperty()
|
||||||
|
{
|
||||||
|
return mAutoStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto-start order property. Indicates the order for starting channels that are flagged for auto-start.
|
||||||
|
*/
|
||||||
|
public IntegerProperty autoStartOrderProperty()
|
||||||
|
{
|
||||||
|
return mAutoStartOrder;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unique identifier for this channel. Value is transient (not persisted).
|
* Unique identifier for this channel. Value is transient (not persisted).
|
||||||
*/
|
*/
|
||||||
@@ -214,17 +291,17 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "system")
|
@JacksonXmlProperty(isAttribute = true, localName = "system")
|
||||||
public String getSystem()
|
public String getSystem()
|
||||||
{
|
{
|
||||||
return mSystem;
|
return mSystem.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSystem(String system)
|
public void setSystem(String system)
|
||||||
{
|
{
|
||||||
mSystem = system;
|
mSystem.set(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSystem()
|
public boolean hasSystem()
|
||||||
{
|
{
|
||||||
return mSystem != null;
|
return mSystem != null && mSystem.get() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -233,17 +310,17 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "site")
|
@JacksonXmlProperty(isAttribute = true, localName = "site")
|
||||||
public String getSite()
|
public String getSite()
|
||||||
{
|
{
|
||||||
return mSite;
|
return mSite.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setSite(String site)
|
public void setSite(String site)
|
||||||
{
|
{
|
||||||
mSite = site;
|
mSite.set(site);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSite()
|
public boolean hasSite()
|
||||||
{
|
{
|
||||||
return mSite != null;
|
return mSite != null && mSite.get() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -252,7 +329,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "name")
|
@JacksonXmlProperty(isAttribute = true, localName = "name")
|
||||||
public String getName()
|
public String getName()
|
||||||
{
|
{
|
||||||
return mName;
|
return mName.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -260,7 +337,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
*/
|
*/
|
||||||
public void setName(String name)
|
public void setName(String name)
|
||||||
{
|
{
|
||||||
mName = name;
|
mName.set(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -284,7 +361,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isProcessing()
|
public boolean isProcessing()
|
||||||
{
|
{
|
||||||
return mProcessing;
|
return mProcessing.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -296,7 +373,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
*/
|
*/
|
||||||
void setProcessing(boolean processing)
|
void setProcessing(boolean processing)
|
||||||
{
|
{
|
||||||
mProcessing = processing;
|
mProcessing.set(processing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,7 +387,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "enabled")
|
@JacksonXmlProperty(isAttribute = true, localName = "enabled")
|
||||||
public boolean getAutoStart()
|
public boolean getAutoStart()
|
||||||
{
|
{
|
||||||
return mAutoStart;
|
return mAutoStart.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -319,7 +396,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean isAutoStart()
|
public boolean isAutoStart()
|
||||||
{
|
{
|
||||||
return mAutoStart;
|
return mAutoStart.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -329,7 +406,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
*/
|
*/
|
||||||
public void setAutoStart(boolean autoStart)
|
public void setAutoStart(boolean autoStart)
|
||||||
{
|
{
|
||||||
mAutoStart = autoStart;
|
mAutoStart.set(autoStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -341,7 +418,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JacksonXmlProperty(isAttribute = true, localName = "order")
|
@JacksonXmlProperty(isAttribute = true, localName = "order")
|
||||||
public Integer getAutoStartOrder()
|
public Integer getAutoStartOrder()
|
||||||
{
|
{
|
||||||
return mAutoStartOrder;
|
return mAutoStartOrder.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -351,7 +428,14 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
*/
|
*/
|
||||||
public void setAutoStartOrder(Integer order)
|
public void setAutoStartOrder(Integer order)
|
||||||
{
|
{
|
||||||
mAutoStartOrder = order;
|
if(order != null)
|
||||||
|
{
|
||||||
|
mAutoStartOrder.set(order);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mAutoStartOrder.setValue(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -362,7 +446,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public boolean hasAutoStartOrder()
|
public boolean hasAutoStartOrder()
|
||||||
{
|
{
|
||||||
return mAutoStartOrder != null;
|
return mAutoStartOrder != null && mAutoStartOrder.getValue() != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -372,7 +456,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
@JacksonXmlProperty(isAttribute = false, localName = "alias_list_name")
|
@JacksonXmlProperty(isAttribute = false, localName = "alias_list_name")
|
||||||
public String getAliasListName()
|
public String getAliasListName()
|
||||||
{
|
{
|
||||||
return mAliasListName;
|
return mAliasListName.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -381,15 +465,7 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
*/
|
*/
|
||||||
public void setAliasListName(String name)
|
public void setAliasListName(String name)
|
||||||
{
|
{
|
||||||
mAliasListName = name;
|
mAliasListName.set(name);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if this channel has a non-null, non-empty alias list name specified.
|
|
||||||
*/
|
|
||||||
public boolean hasAliasList()
|
|
||||||
{
|
|
||||||
return mAliasListName != null && !mAliasListName.isEmpty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -558,8 +634,6 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Current channel frequency correction value (when this channel is processing)
|
* Current channel frequency correction value (when this channel is processing)
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
*/
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
public int getChannelFrequencyCorrection()
|
public int getChannelFrequencyCorrection()
|
||||||
@@ -595,4 +669,13 @@ public class Channel extends Configuration implements Listener<SourceEvent>
|
|||||||
{
|
{
|
||||||
return Objects.hash(getChannelID());
|
return Objects.hash(getChannelID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an observable property extractor for use with observable lists to detect changes internal to this object.
|
||||||
|
*/
|
||||||
|
public static Callback<Channel,Observable[]> extractor()
|
||||||
|
{
|
||||||
|
return (Channel c) -> new Observable[] {c.processingProperty(), c.nameProperty(), c.aliasListNameProperty(),
|
||||||
|
c.autoStartOrderProperty(), c.autoStartProperty(), c.siteProperty(), c.systemProperty()};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,306 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2019 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.controller.channel;
|
|
||||||
|
|
||||||
import com.jidesoft.swing.JideSplitPane;
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
|
|
||||||
import io.github.dsheirer.preference.UserPreferences;
|
|
||||||
import io.github.dsheirer.preference.swing.JTableColumnWidthMonitor;
|
|
||||||
import io.github.dsheirer.source.SourceManager;
|
|
||||||
import net.coderazzi.filters.gui.AutoChoices;
|
|
||||||
import net.coderazzi.filters.gui.TableFilterHeader;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import javax.swing.JPanel;
|
|
||||||
import javax.swing.JScrollPane;
|
|
||||||
import javax.swing.JTable;
|
|
||||||
import javax.swing.ListSelectionModel;
|
|
||||||
import javax.swing.event.ListSelectionEvent;
|
|
||||||
import javax.swing.event.ListSelectionListener;
|
|
||||||
import javax.swing.table.DefaultTableCellRenderer;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
|
||||||
import java.awt.Rectangle;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class ChannelController extends JPanel implements ActionListener, ListSelectionListener
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
private static final String TABLE_PREFERENCE_KEY = "channel.controller";
|
|
||||||
private ChannelModel mChannelModel;
|
|
||||||
private ChannelProcessingManager mChannelProcessingManager;
|
|
||||||
private JTable mChannelTable;
|
|
||||||
private JTableColumnWidthMonitor mColumnWidthMonitor;
|
|
||||||
private TableFilterHeader mTableFilterHeader;
|
|
||||||
private ChannelEditor mEditor;
|
|
||||||
private UserPreferences mUserPreferences;
|
|
||||||
|
|
||||||
private static final String NEW_CHANNEL = "New";
|
|
||||||
private static final String COPY_CHANNEL = "Copy";
|
|
||||||
private static final String DELETE_CHANNEL = "Delete";
|
|
||||||
|
|
||||||
private JButton mNewChannelButton = new JButton(NEW_CHANNEL);
|
|
||||||
private JButton mCopyChannelButton = new JButton(COPY_CHANNEL);
|
|
||||||
private JButton mDeleteChannelButton = new JButton(DELETE_CHANNEL);
|
|
||||||
|
|
||||||
public ChannelController(ChannelModel channelModel, ChannelProcessingManager channelProcessingManager,
|
|
||||||
ChannelMapModel channelMapModel, SourceManager sourceManager, AliasModel aliasModel,
|
|
||||||
UserPreferences userPreferences)
|
|
||||||
{
|
|
||||||
mChannelModel = channelModel;
|
|
||||||
mChannelProcessingManager = channelProcessingManager;
|
|
||||||
mEditor = new ChannelEditor(channelModel, channelProcessingManager, channelMapModel, sourceManager, aliasModel);
|
|
||||||
mChannelModel.addListener(mEditor);
|
|
||||||
mChannelProcessingManager.addChannelEventListener(mEditor);
|
|
||||||
mUserPreferences = userPreferences;
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("", "[grow,fill]", "[grow,fill]"));
|
|
||||||
|
|
||||||
//System Configuration View and Editor
|
|
||||||
mChannelTable = new JTable(mChannelModel);
|
|
||||||
mChannelTable.setDefaultRenderer(String.class, new ChannelTableCellRenderer());
|
|
||||||
mChannelTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
mChannelTable.getSelectionModel().addListSelectionListener(this);
|
|
||||||
mChannelTable.setAutoCreateRowSorter(true);
|
|
||||||
mColumnWidthMonitor = new JTableColumnWidthMonitor(mUserPreferences, mChannelTable, TABLE_PREFERENCE_KEY);
|
|
||||||
|
|
||||||
mTableFilterHeader = new TableFilterHeader(mChannelTable, AutoChoices.ENABLED);
|
|
||||||
mTableFilterHeader.setFilterOnUpdates(true);
|
|
||||||
|
|
||||||
JScrollPane channelScroller = new JScrollPane(mChannelTable);
|
|
||||||
|
|
||||||
JPanel buttonsPanel = new JPanel();
|
|
||||||
|
|
||||||
buttonsPanel.setLayout(
|
|
||||||
new MigLayout("insets 0 0 0 0", "[grow,fill][grow,fill][grow,fill]", "[]"));
|
|
||||||
|
|
||||||
mNewChannelButton.addActionListener(this);
|
|
||||||
mNewChannelButton.setToolTipText("Create a new channel configuration");
|
|
||||||
buttonsPanel.add(mNewChannelButton);
|
|
||||||
|
|
||||||
mCopyChannelButton.addActionListener(this);
|
|
||||||
mCopyChannelButton.setEnabled(false);
|
|
||||||
mCopyChannelButton.setToolTipText("Create a copy of the currently selected channel configuration");
|
|
||||||
buttonsPanel.add(mCopyChannelButton);
|
|
||||||
|
|
||||||
mDeleteChannelButton.addActionListener(this);
|
|
||||||
mDeleteChannelButton.setEnabled(false);
|
|
||||||
mDeleteChannelButton.setToolTipText("Delete the currently selected channel configuration");
|
|
||||||
buttonsPanel.add(mDeleteChannelButton);
|
|
||||||
|
|
||||||
JPanel listAndButtonsPanel = new JPanel();
|
|
||||||
|
|
||||||
listAndButtonsPanel.setLayout(
|
|
||||||
new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill][]"));
|
|
||||||
|
|
||||||
listAndButtonsPanel.add(channelScroller, "wrap");
|
|
||||||
listAndButtonsPanel.add(buttonsPanel);
|
|
||||||
|
|
||||||
JideSplitPane splitPane = new JideSplitPane(JideSplitPane.VERTICAL_SPLIT);
|
|
||||||
splitPane.setDividerSize(5);
|
|
||||||
splitPane.setShowGripper(true);
|
|
||||||
|
|
||||||
//Shrink this guy so that he'll eventually be expanded to the scroller preferred size
|
|
||||||
listAndButtonsPanel.setPreferredSize(new Dimension(10, 10));
|
|
||||||
|
|
||||||
//Attempt to get a 60:40 vertical sizing preference
|
|
||||||
JScrollPane listScroller = new JScrollPane(listAndButtonsPanel);
|
|
||||||
listScroller.setPreferredSize(new Dimension(800, 58));
|
|
||||||
|
|
||||||
JScrollPane editorScroller = new JScrollPane(mEditor);
|
|
||||||
editorScroller.setPreferredSize(new Dimension(800, 42));
|
|
||||||
|
|
||||||
splitPane.add(listScroller);
|
|
||||||
splitPane.add(editorScroller);
|
|
||||||
|
|
||||||
add(splitPane);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void valueChanged(ListSelectionEvent event)
|
|
||||||
{
|
|
||||||
//This limits event firing to only when selection is complete
|
|
||||||
if(!event.getValueIsAdjusting())
|
|
||||||
{
|
|
||||||
int selectedRow = mChannelTable.getSelectedRow();
|
|
||||||
|
|
||||||
if(selectedRow != -1)
|
|
||||||
{
|
|
||||||
int index = mChannelTable.convertRowIndexToModel(mChannelTable.getSelectedRow());
|
|
||||||
|
|
||||||
Channel channel = mChannelModel.getChannelAtIndex(index);
|
|
||||||
|
|
||||||
if(channel != null)
|
|
||||||
{
|
|
||||||
mEditor.setItem(channel);
|
|
||||||
mCopyChannelButton.setEnabled(true);
|
|
||||||
mDeleteChannelButton.setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mEditor.setItem(null);
|
|
||||||
mCopyChannelButton.setEnabled(false);
|
|
||||||
mDeleteChannelButton.setEnabled(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the channel to the channel model/table and scrolls to view it
|
|
||||||
*/
|
|
||||||
private void addChannel(Channel channel)
|
|
||||||
{
|
|
||||||
//HACK: when inserting a row to the model, the JTable gets
|
|
||||||
//notified and attempts to tell the coderazzi table filter
|
|
||||||
//adaptive choices filter to refresh before the table filter is
|
|
||||||
//notified of the row additions, causing an index out of bounds
|
|
||||||
//exception. We turn off adaptive choices temporarily, add the
|
|
||||||
//channel, and turn on adaptive choices again.
|
|
||||||
mTableFilterHeader.setAdaptiveChoices(false);
|
|
||||||
|
|
||||||
int index = mChannelModel.addChannel(channel);
|
|
||||||
|
|
||||||
mTableFilterHeader.setAdaptiveChoices(true);
|
|
||||||
|
|
||||||
if(index >= 0)
|
|
||||||
{
|
|
||||||
int translatedIndex = mChannelTable.convertRowIndexToView(index);
|
|
||||||
|
|
||||||
if(translatedIndex >= 0)
|
|
||||||
{
|
|
||||||
mChannelTable.setRowSelectionInterval(translatedIndex, translatedIndex);
|
|
||||||
mChannelTable.scrollRectToVisible(
|
|
||||||
new Rectangle(mChannelTable.getCellRect(translatedIndex, 0, true)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Channel getSelectedChannel()
|
|
||||||
{
|
|
||||||
int index = mChannelTable.getSelectedRow();
|
|
||||||
|
|
||||||
if(index >= 0)
|
|
||||||
{
|
|
||||||
return mChannelModel.getChannelAtIndex(
|
|
||||||
mChannelTable.convertRowIndexToModel(index));
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responds to New, Copy and Delete Channel button invocations
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent event)
|
|
||||||
{
|
|
||||||
switch(event.getActionCommand())
|
|
||||||
{
|
|
||||||
case NEW_CHANNEL:
|
|
||||||
addChannel(new Channel("New Channel"));
|
|
||||||
break;
|
|
||||||
case COPY_CHANNEL:
|
|
||||||
Channel selected = getSelectedChannel();
|
|
||||||
|
|
||||||
if(selected != null)
|
|
||||||
{
|
|
||||||
addChannel(selected.copyOf());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DELETE_CHANNEL:
|
|
||||||
Channel toDelete = getSelectedChannel();
|
|
||||||
|
|
||||||
if(toDelete != null)
|
|
||||||
{
|
|
||||||
int choice = JOptionPane.showConfirmDialog(ChannelController.this,
|
|
||||||
"Do you want to delete this channel?", "Delete Channel?",
|
|
||||||
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
|
|
||||||
|
|
||||||
if(choice == JOptionPane.YES_OPTION)
|
|
||||||
{
|
|
||||||
mChannelModel.removeChannel(toDelete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ChannelTableCellRenderer extends DefaultTableCellRenderer
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getTableCellRendererComponent(JTable table,
|
|
||||||
Object value, boolean isSelected, boolean hasFocus, int row,
|
|
||||||
int column)
|
|
||||||
{
|
|
||||||
Component component = super.getTableCellRendererComponent(
|
|
||||||
table, value, isSelected, hasFocus, row, column);
|
|
||||||
|
|
||||||
ChannelModel model = (ChannelModel)table.getModel();
|
|
||||||
|
|
||||||
int index = table.convertRowIndexToModel(row);
|
|
||||||
|
|
||||||
Channel channel = model.getChannelAtIndex(index);
|
|
||||||
|
|
||||||
boolean enabled = channel.isProcessing();
|
|
||||||
|
|
||||||
if(isSelected)
|
|
||||||
{
|
|
||||||
if(enabled)
|
|
||||||
{
|
|
||||||
component.setBackground(Color.YELLOW);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
component.setBackground(table.getSelectionBackground());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(enabled)
|
|
||||||
{
|
|
||||||
component.setBackground(Color.GREEN);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
component.setBackground(table.getBackground());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return component;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
/*
|
|
||||||
* ******************************************************************************
|
|
||||||
* sdrtrunk
|
|
||||||
* Copyright (C) 2014-2018 Dennis Sheirer
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
* *****************************************************************************
|
|
||||||
*/
|
|
||||||
package io.github.dsheirer.controller.channel;
|
|
||||||
|
|
||||||
import com.jidesoft.swing.JideTabbedPane;
|
|
||||||
import io.github.dsheirer.alias.AliasModel;
|
|
||||||
import io.github.dsheirer.controller.channel.map.ChannelMapModel;
|
|
||||||
import io.github.dsheirer.gui.editor.Editor;
|
|
||||||
import io.github.dsheirer.gui.editor.EditorValidationException;
|
|
||||||
import io.github.dsheirer.module.decode.AuxDecodeConfigurationEditor;
|
|
||||||
import io.github.dsheirer.module.decode.DecodeConfigurationEditor;
|
|
||||||
import io.github.dsheirer.module.log.EventLogConfigurationEditor;
|
|
||||||
import io.github.dsheirer.record.RecordConfigurationEditor;
|
|
||||||
import io.github.dsheirer.sample.Listener;
|
|
||||||
import io.github.dsheirer.source.SourceConfigurationEditor;
|
|
||||||
import io.github.dsheirer.source.SourceManager;
|
|
||||||
import net.miginfocom.swing.MigLayout;
|
|
||||||
|
|
||||||
import javax.swing.JButton;
|
|
||||||
import javax.swing.JLabel;
|
|
||||||
import javax.swing.JOptionPane;
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
|
|
||||||
public class ChannelEditor extends Editor<Channel> implements ActionListener, Listener<ChannelEvent>
|
|
||||||
{
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
private static final String ACTION_START = "Start";
|
|
||||||
private static final String ACTION_STOP = "Stop";
|
|
||||||
private static final String ACTION_SAVE = "Save";
|
|
||||||
private static final String ACTION_RESET = "Reset";
|
|
||||||
|
|
||||||
private NameConfigurationEditor mNameConfigurationEditor;
|
|
||||||
private SourceConfigurationEditor mSourceConfigurationEditor;
|
|
||||||
private DecodeConfigurationEditor mDecodeConfigurationEditor;
|
|
||||||
private AuxDecodeConfigurationEditor mAuxDecodeConfigurationEditor;
|
|
||||||
private EventLogConfigurationEditor mEventLogConfigurationEditor;
|
|
||||||
private RecordConfigurationEditor mRecordConfigurationEditor;
|
|
||||||
|
|
||||||
private JButton mProcessingStateButton = new JButton(ACTION_START);
|
|
||||||
private JLabel mChannelName = new JLabel("Channel:");
|
|
||||||
|
|
||||||
private ChannelModel mChannelModel;
|
|
||||||
private ChannelProcessingManager mChannelProcessingManager;
|
|
||||||
private ChannelMapModel mChannelMapModel;
|
|
||||||
private SourceManager mSourceManager;
|
|
||||||
|
|
||||||
private boolean mChannelStartRequested = false;
|
|
||||||
|
|
||||||
public ChannelEditor(ChannelModel channelModel,
|
|
||||||
ChannelProcessingManager channelProcessingManager,
|
|
||||||
ChannelMapModel channelMapModel,
|
|
||||||
SourceManager sourceManager,
|
|
||||||
AliasModel aliasModel)
|
|
||||||
{
|
|
||||||
mChannelModel = channelModel;
|
|
||||||
mChannelProcessingManager = channelProcessingManager;
|
|
||||||
mChannelMapModel = channelMapModel;
|
|
||||||
mSourceManager = sourceManager;
|
|
||||||
mNameConfigurationEditor = new NameConfigurationEditor(aliasModel, mChannelModel);
|
|
||||||
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void init()
|
|
||||||
{
|
|
||||||
setLayout(new MigLayout("fill,wrap 3", "[grow,fill][grow,fill][grow,fill]", "[grow,fill][]"));
|
|
||||||
|
|
||||||
JideTabbedPane tabs = new JideTabbedPane();
|
|
||||||
tabs.setFont(this.getFont());
|
|
||||||
tabs.setForeground(Color.BLACK);
|
|
||||||
|
|
||||||
tabs.setTabTrailingComponent(mChannelName);
|
|
||||||
|
|
||||||
mNameConfigurationEditor.setSaveRequestListener(this);
|
|
||||||
tabs.addTab("Name/Alias", mNameConfigurationEditor);
|
|
||||||
|
|
||||||
mSourceConfigurationEditor = new SourceConfigurationEditor(mSourceManager);
|
|
||||||
mSourceConfigurationEditor.setSaveRequestListener(this);
|
|
||||||
tabs.addTab("Source", mSourceConfigurationEditor);
|
|
||||||
|
|
||||||
mDecodeConfigurationEditor = new DecodeConfigurationEditor(mChannelMapModel);
|
|
||||||
mDecodeConfigurationEditor.setSaveRequestListener(this);
|
|
||||||
tabs.addTab("Decoder", mDecodeConfigurationEditor);
|
|
||||||
|
|
||||||
mAuxDecodeConfigurationEditor = new AuxDecodeConfigurationEditor();
|
|
||||||
mAuxDecodeConfigurationEditor.setSaveRequestListener(this);
|
|
||||||
tabs.addTab("Aux Decoders", mAuxDecodeConfigurationEditor);
|
|
||||||
|
|
||||||
mEventLogConfigurationEditor = new EventLogConfigurationEditor();
|
|
||||||
mEventLogConfigurationEditor.setSaveRequestListener(this);
|
|
||||||
tabs.addTab("Logging", mEventLogConfigurationEditor);
|
|
||||||
|
|
||||||
mRecordConfigurationEditor = new RecordConfigurationEditor();
|
|
||||||
mRecordConfigurationEditor.setSaveRequestListener(this);
|
|
||||||
tabs.addTab("Recording", mRecordConfigurationEditor);
|
|
||||||
|
|
||||||
add(tabs, "span");
|
|
||||||
|
|
||||||
mProcessingStateButton.addActionListener(this);
|
|
||||||
mProcessingStateButton.setEnabled(false);
|
|
||||||
mProcessingStateButton.setToolTipText("Start/Stop the currently selected channel");
|
|
||||||
add(mProcessingStateButton);
|
|
||||||
|
|
||||||
JButton btnSave = new JButton(ACTION_SAVE);
|
|
||||||
btnSave.setToolTipText("Save changes to the currently selected channel");
|
|
||||||
btnSave.addActionListener(ChannelEditor.this);
|
|
||||||
add(btnSave);
|
|
||||||
|
|
||||||
JButton btnReset = new JButton(ACTION_RESET);
|
|
||||||
btnReset.setToolTipText("Reload the currently selected channel");
|
|
||||||
btnReset.addActionListener(ChannelEditor.this);
|
|
||||||
add(btnReset);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void receive(ChannelEvent event)
|
|
||||||
{
|
|
||||||
if(hasItem() && getItem() == event.getChannel())
|
|
||||||
{
|
|
||||||
switch(event.getEvent())
|
|
||||||
{
|
|
||||||
case NOTIFICATION_CONFIGURATION_CHANGE:
|
|
||||||
case NOTIFICATION_PROCESSING_START:
|
|
||||||
case NOTIFICATION_PROCESSING_STOP:
|
|
||||||
setItem(getItem());
|
|
||||||
mChannelStartRequested = false;
|
|
||||||
break;
|
|
||||||
case NOTIFICATION_DELETE:
|
|
||||||
setItem(null);
|
|
||||||
break;
|
|
||||||
case NOTIFICATION_PROCESSING_START_REJECTED:
|
|
||||||
if(mChannelStartRequested)
|
|
||||||
{
|
|
||||||
JOptionPane.showMessageDialog(ChannelEditor.this, "Channel could not be "
|
|
||||||
+ "started. This is likely because there are no tuner channels "
|
|
||||||
+ "available", "Couldn't start channel", JOptionPane.INFORMATION_MESSAGE);
|
|
||||||
|
|
||||||
mChannelStartRequested = false;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e)
|
|
||||||
{
|
|
||||||
String command = e.getActionCommand();
|
|
||||||
|
|
||||||
if(command.contentEquals(ACTION_START))
|
|
||||||
{
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
|
|
||||||
mChannelStartRequested = true;
|
|
||||||
mChannelProcessingManager.receive(new ChannelEvent(getItem(), ChannelEvent.Event.REQUEST_ENABLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(command.contentEquals(ACTION_STOP))
|
|
||||||
{
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
mChannelProcessingManager.receive(new ChannelEvent(getItem(), ChannelEvent.Event.REQUEST_DISABLE));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if(command.contentEquals(ACTION_SAVE))
|
|
||||||
{
|
|
||||||
save();
|
|
||||||
}
|
|
||||||
else if(command.contentEquals(ACTION_RESET))
|
|
||||||
{
|
|
||||||
setItem(getItem());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the channel configuration in each of the channel editor components
|
|
||||||
* Note: this method must be invoked on the swing event dispatch thread
|
|
||||||
*/
|
|
||||||
public void setItem(final Channel channel)
|
|
||||||
{
|
|
||||||
super.setItem(channel);
|
|
||||||
|
|
||||||
mNameConfigurationEditor.setItem(channel);
|
|
||||||
mSourceConfigurationEditor.setItem(channel);
|
|
||||||
mDecodeConfigurationEditor.setItem(channel);
|
|
||||||
mAuxDecodeConfigurationEditor.setItem(channel);
|
|
||||||
mEventLogConfigurationEditor.setItem(channel);
|
|
||||||
mRecordConfigurationEditor.setItem(channel);
|
|
||||||
|
|
||||||
if(channel != null)
|
|
||||||
{
|
|
||||||
mChannelName.setText("Channel: " + channel.getName());
|
|
||||||
mProcessingStateButton.setText(channel.isProcessing() ? ACTION_STOP : ACTION_START);
|
|
||||||
mProcessingStateButton.setEnabled(true);
|
|
||||||
mProcessingStateButton.setBackground(channel.isProcessing() ? Color.GREEN : getBackground());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mChannelName.setText("Channel: ");
|
|
||||||
mProcessingStateButton.setText(ACTION_START);
|
|
||||||
mProcessingStateButton.setEnabled(false);
|
|
||||||
mProcessingStateButton.setBackground(getBackground());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save()
|
|
||||||
{
|
|
||||||
if(hasItem())
|
|
||||||
{
|
|
||||||
mNameConfigurationEditor.save();
|
|
||||||
mSourceConfigurationEditor.save();
|
|
||||||
mDecodeConfigurationEditor.save();
|
|
||||||
mAuxDecodeConfigurationEditor.save();
|
|
||||||
mEventLogConfigurationEditor.save();
|
|
||||||
mRecordConfigurationEditor.save();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
mDecodeConfigurationEditor.validate(mSourceConfigurationEditor);
|
|
||||||
mDecodeConfigurationEditor.validate(mAuxDecodeConfigurationEditor);
|
|
||||||
}
|
|
||||||
catch(EditorValidationException e)
|
|
||||||
{
|
|
||||||
e.getEditor().requestFocus();
|
|
||||||
|
|
||||||
JOptionPane.showMessageDialog(e.getEditor(), e.getReason(),
|
|
||||||
"Configuration Error", JOptionPane.ERROR_MESSAGE);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChannelEvent update = new ChannelEvent(getItem(), ChannelEvent.Event.NOTIFICATION_CONFIGURATION_CHANGE);
|
|
||||||
|
|
||||||
mChannelModel.receive(update);
|
|
||||||
}
|
|
||||||
|
|
||||||
setModified(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -80,6 +80,22 @@ public class ChannelEvent
|
|||||||
(mDescription != null ? " Description:" + mDescription : "");
|
(mDescription != null ? " Description:" + mDescription : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a request enable channel event
|
||||||
|
*/
|
||||||
|
public static ChannelEvent requestEnable(Channel channel)
|
||||||
|
{
|
||||||
|
return new ChannelEvent(channel, Event.REQUEST_ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new request disable channel event
|
||||||
|
*/
|
||||||
|
public static ChannelEvent requestDisable(Channel channel)
|
||||||
|
{
|
||||||
|
return new ChannelEvent(channel, Event.REQUEST_DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel events to describe the specific event
|
* Channel events to describe the specific event
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* SDR Trunk
|
||||||
|
* Copyright (C) 2014 Dennis Sheirer
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
******************************************************************************/
|
||||||
|
package io.github.dsheirer.controller.channel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception for channel start/stop errors
|
||||||
|
*/
|
||||||
|
public class ChannelException extends Exception
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public ChannelException(String message )
|
||||||
|
{
|
||||||
|
this( message, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ChannelException(String message, Throwable cause )
|
||||||
|
{
|
||||||
|
super( message, cause );
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,62 +1,94 @@
|
|||||||
/*******************************************************************************
|
/*
|
||||||
* 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
|
* * Copyright (C) 2014-2020 Dennis Sheirer
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* *
|
||||||
* (at your option) any later version.
|
* * This program is free software: you can redistribute it and/or modify
|
||||||
|
* * it under the terms of the GNU General Public License as published by
|
||||||
|
* * the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* * (at your option) any later version.
|
||||||
|
* *
|
||||||
|
* * This program is distributed in the hope that it will be useful,
|
||||||
|
* * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* * GNU General Public License for more details.
|
||||||
|
* *
|
||||||
|
* * You should have received a copy of the GNU General Public License
|
||||||
|
* * along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
* * *****************************************************************************
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
*/
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
package io.github.dsheirer.controller.channel;
|
package io.github.dsheirer.controller.channel;
|
||||||
|
|
||||||
|
import io.github.dsheirer.alias.AliasModel;
|
||||||
import io.github.dsheirer.controller.channel.Channel.ChannelType;
|
import io.github.dsheirer.controller.channel.Channel.ChannelType;
|
||||||
import io.github.dsheirer.controller.channel.ChannelEvent.Event;
|
import io.github.dsheirer.controller.channel.ChannelEvent.Event;
|
||||||
import io.github.dsheirer.module.decode.DecoderType;
|
|
||||||
import io.github.dsheirer.sample.Broadcaster;
|
import io.github.dsheirer.sample.Broadcaster;
|
||||||
import io.github.dsheirer.sample.Listener;
|
import io.github.dsheirer.sample.Listener;
|
||||||
|
import javafx.collections.FXCollections;
|
||||||
|
import javafx.collections.ListChangeListener;
|
||||||
|
import javafx.collections.ObservableList;
|
||||||
|
|
||||||
import javax.swing.table.AbstractTableModel;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Channel Model
|
* Channel Model
|
||||||
*/
|
*/
|
||||||
public class ChannelModel extends AbstractTableModel implements Listener<ChannelEvent>
|
public class ChannelModel implements Listener<ChannelEvent>
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private ObservableList<Channel> mChannels = FXCollections.observableArrayList(Channel.extractor());
|
||||||
|
private ObservableList<Channel> mTrafficChannels = FXCollections.observableArrayList(Channel.extractor());
|
||||||
public static final int COLUMN_ENABLED = 0;
|
|
||||||
public static final int COLUMN_SYSTEM = 1;
|
|
||||||
public static final int COLUMN_SITE = 2;
|
|
||||||
public static final int COLUMN_NAME = 3;
|
|
||||||
public static final int COLUMN_ALIAS_LIST = 4;
|
|
||||||
public static final int COLUMN_SOURCE = 5;
|
|
||||||
public static final int COLUMN_DECODER = 6;
|
|
||||||
public static final int COLUMN_AUTO_START = 7;
|
|
||||||
|
|
||||||
private static final String[] COLUMN_NAMES = new String[] {"Playing", "System", "Site", "Name", "Alias List",
|
|
||||||
"Source", "Decoder", "Auto-Start"};
|
|
||||||
private static final String VALUE_YES = "Yes";
|
|
||||||
|
|
||||||
private List<Channel> mChannels = new CopyOnWriteArrayList<>();
|
|
||||||
private List<Channel> mTrafficChannels = new CopyOnWriteArrayList<>();
|
|
||||||
private Broadcaster<ChannelEvent> mChannelEventBroadcaster = new Broadcaster();
|
private Broadcaster<ChannelEvent> mChannelEventBroadcaster = new Broadcaster();
|
||||||
|
private AliasModel mAliasModel;
|
||||||
|
|
||||||
public ChannelModel()
|
public ChannelModel(AliasModel aliasModel)
|
||||||
{
|
{
|
||||||
|
mAliasModel = aliasModel;
|
||||||
|
|
||||||
|
//Register a listener to detect channel changes and broadcast change events to cause playlist save requests
|
||||||
|
ChannelListChangeListener changeListener = new ChannelListChangeListener();
|
||||||
|
mChannels.addListener(changeListener);
|
||||||
|
mTrafficChannels.addListener(changeListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable list of channel configurations managed by this model
|
||||||
|
*/
|
||||||
|
public ObservableList<Channel> channelList()
|
||||||
|
{
|
||||||
|
return mChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observable list of traffic channel configurations managed by this model
|
||||||
|
*/
|
||||||
|
public ObservableList<Channel> trafficChannelList()
|
||||||
|
{
|
||||||
|
return mTrafficChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all channels and traffic channels and fires remove event for each.
|
||||||
|
*/
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
List<Channel> trafficChannels = new ArrayList<>(mTrafficChannels);
|
||||||
|
|
||||||
|
for(Channel trafficChannel: trafficChannels)
|
||||||
|
{
|
||||||
|
removeChannel(trafficChannel);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Channel> channels = new ArrayList<>(mChannels);
|
||||||
|
|
||||||
|
for(Channel channel: channels)
|
||||||
|
{
|
||||||
|
removeChannel(channel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -80,7 +112,7 @@ public class ChannelModel extends AbstractTableModel implements Listener<Channel
|
|||||||
/**
|
/**
|
||||||
* Returns a list of unique system values from across the channel set
|
* Returns a list of unique system values from across the channel set
|
||||||
*/
|
*/
|
||||||
public List<String> getSystems()
|
public List<String> getSystemNames()
|
||||||
{
|
{
|
||||||
List<String> systems = new ArrayList<>();
|
List<String> systems = new ArrayList<>();
|
||||||
|
|
||||||
@@ -97,33 +129,6 @@ public class ChannelModel extends AbstractTableModel implements Listener<Channel
|
|||||||
return systems;
|
return systems;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of unique site values for all channels that have a matching
|
|
||||||
* system value
|
|
||||||
*/
|
|
||||||
public List<String> getSites(String system)
|
|
||||||
{
|
|
||||||
List<String> sites = new ArrayList<>();
|
|
||||||
|
|
||||||
if(system != null)
|
|
||||||
{
|
|
||||||
for(Channel channel : mChannels)
|
|
||||||
{
|
|
||||||
if(channel.hasSystem() &&
|
|
||||||
system.equals(channel.getSystem()) &&
|
|
||||||
channel.hasSite() &&
|
|
||||||
!sites.contains(channel.getSite()))
|
|
||||||
{
|
|
||||||
sites.add(channel.getSite());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Collections.sort(sites);
|
|
||||||
|
|
||||||
return sites;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Broadcasts the channel event to all registered listeners
|
* Broadcasts the channel event to all registered listeners
|
||||||
*/
|
*/
|
||||||
@@ -136,22 +141,9 @@ public class ChannelModel extends AbstractTableModel implements Listener<Channel
|
|||||||
{
|
{
|
||||||
case NOTIFICATION_CONFIGURATION_CHANGE:
|
case NOTIFICATION_CONFIGURATION_CHANGE:
|
||||||
case NOTIFICATION_SELECTION_CHANGE:
|
case NOTIFICATION_SELECTION_CHANGE:
|
||||||
index = mChannels.indexOf(event.getChannel());
|
|
||||||
if(index > 0)
|
|
||||||
{
|
|
||||||
fireTableRowsUpdated(index, index);
|
|
||||||
}
|
|
||||||
//rebroadcast this event to any listeners
|
//rebroadcast this event to any listeners
|
||||||
mChannelEventBroadcaster.broadcast(event);
|
mChannelEventBroadcaster.broadcast(event);
|
||||||
break;
|
break;
|
||||||
case NOTIFICATION_PROCESSING_START:
|
|
||||||
case NOTIFICATION_PROCESSING_STOP:
|
|
||||||
index = mChannels.indexOf(event.getChannel());
|
|
||||||
if(index > 0)
|
|
||||||
{
|
|
||||||
fireTableRowsUpdated(index, index);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -178,30 +170,21 @@ public class ChannelModel extends AbstractTableModel implements Listener<Channel
|
|||||||
/**
|
/**
|
||||||
* Adds the channel to the model and broadcasts a channel add event
|
* Adds the channel to the model and broadcasts a channel add event
|
||||||
*/
|
*/
|
||||||
public int addChannel(Channel channel)
|
public void addChannel(Channel channel)
|
||||||
{
|
{
|
||||||
int index = -1;
|
|
||||||
|
|
||||||
switch(channel.getChannelType())
|
switch(channel.getChannelType())
|
||||||
{
|
{
|
||||||
case STANDARD:
|
case STANDARD:
|
||||||
mChannels.add(channel);
|
mChannels.add(channel);
|
||||||
|
//Make sure the alias model has the alias list referred to by the channel
|
||||||
index = mChannels.size() - 1;
|
mAliasModel.addAliasList(channel.getAliasListName());
|
||||||
|
|
||||||
fireTableRowsInserted(index, index);
|
|
||||||
break;
|
break;
|
||||||
case TRAFFIC:
|
case TRAFFIC:
|
||||||
mTrafficChannels.add(channel);
|
mTrafficChannels.add(channel);
|
||||||
index = mChannels.size() - 1;
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_ADD));
|
|
||||||
|
|
||||||
return index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -214,14 +197,7 @@ public class ChannelModel extends AbstractTableModel implements Listener<Channel
|
|||||||
switch(channel.getChannelType())
|
switch(channel.getChannelType())
|
||||||
{
|
{
|
||||||
case STANDARD:
|
case STANDARD:
|
||||||
int index = mChannels.indexOf(channel);
|
|
||||||
|
|
||||||
mChannels.remove(channel);
|
mChannels.remove(channel);
|
||||||
|
|
||||||
if(index >= 0)
|
|
||||||
{
|
|
||||||
fireTableRowsDeleted(index, index);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case TRAFFIC:
|
case TRAFFIC:
|
||||||
mTrafficChannels.remove(channel);
|
mTrafficChannels.remove(channel);
|
||||||
@@ -229,8 +205,6 @@ public class ChannelModel extends AbstractTableModel implements Listener<Channel
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_DELETE));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,89 +286,59 @@ public class ChannelModel extends AbstractTableModel implements Listener<Channel
|
|||||||
mChannelEventBroadcaster.removeListener(listener);
|
mChannelEventBroadcaster.removeListener(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Table Model Interface Methods - standard channels only
|
/**
|
||||||
@Override
|
* List of site names from all channels in the model
|
||||||
public int getRowCount()
|
*/
|
||||||
|
public List<String> getSiteNames()
|
||||||
{
|
{
|
||||||
return mChannels.size();
|
List<String> sites = new ArrayList<>();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
for(Channel channel: mChannels)
|
||||||
public int getColumnCount()
|
|
||||||
{
|
|
||||||
return COLUMN_NAMES.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getColumnName(int columnIndex)
|
|
||||||
{
|
|
||||||
if(columnIndex < COLUMN_NAMES.length)
|
|
||||||
{
|
{
|
||||||
return COLUMN_NAMES[columnIndex];
|
String site = channel.getSite();
|
||||||
|
|
||||||
|
if(site != null && !site.isEmpty() && !sites.contains(site))
|
||||||
|
{
|
||||||
|
sites.add(site);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return sites;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public Class<?> getColumnClass(int columnIndex)
|
* Observable list change listener for both channels and traffic channels lists
|
||||||
|
*/
|
||||||
|
public class ChannelListChangeListener implements ListChangeListener<Channel>
|
||||||
{
|
{
|
||||||
return String.class;
|
@Override
|
||||||
}
|
public void onChanged(Change<? extends Channel> change)
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValueAt(int rowIndex, int columnIndex)
|
|
||||||
{
|
|
||||||
Channel channel = mChannels.get(rowIndex);
|
|
||||||
|
|
||||||
switch(columnIndex)
|
|
||||||
{
|
{
|
||||||
case COLUMN_ENABLED:
|
while(change.next())
|
||||||
return channel.isProcessing() ? VALUE_YES : null;
|
{
|
||||||
case COLUMN_SYSTEM:
|
if(change.wasAdded())
|
||||||
return channel.getSystem();
|
|
||||||
case COLUMN_SITE:
|
|
||||||
return channel.getSite();
|
|
||||||
case COLUMN_NAME:
|
|
||||||
return channel.getName();
|
|
||||||
case COLUMN_ALIAS_LIST:
|
|
||||||
return channel.getAliasListName();
|
|
||||||
case COLUMN_SOURCE:
|
|
||||||
return channel.getSourceConfiguration().getDescription();
|
|
||||||
case COLUMN_DECODER:
|
|
||||||
return channel.getDecodeConfiguration().getDecoderType().getShortDisplayString();
|
|
||||||
case COLUMN_AUTO_START:
|
|
||||||
if(channel.isAutoStart())
|
|
||||||
{
|
{
|
||||||
if(channel.hasAutoStartOrder())
|
for(Channel channel: change.getAddedSubList())
|
||||||
{
|
{
|
||||||
return channel.getAutoStartOrder();
|
mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_ADD));
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return VALUE_YES;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
else if(change.wasRemoved())
|
||||||
|
{
|
||||||
|
for(Channel channel: change.getRemoved())
|
||||||
|
{
|
||||||
|
mChannelEventBroadcaster.broadcast(new ChannelEvent(channel, Event.NOTIFICATION_DELETE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(change.wasUpdated())
|
||||||
|
{
|
||||||
|
for(int x = change.getFrom(); x < change.getTo(); x++)
|
||||||
|
{
|
||||||
|
mChannelEventBroadcaster.broadcast(new ChannelEvent(change.getList().get(x),
|
||||||
|
Event.NOTIFICATION_CONFIGURATION_CHANGE));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValueAt(Object aValue, int rowIndex, int columnIndex)
|
|
||||||
{
|
|
||||||
throw new IllegalArgumentException("Not yet implemented");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createChannel(DecoderType decoderType, long frequency)
|
|
||||||
{
|
|
||||||
throw new UnsupportedOperationException("Not yet implemented");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user