#2277 Enhances playlist manager with accessibility features to better support assistive technology like screen readers on Windows and OSX. (#2583)

Co-authored-by: sheirerd <sheirerd@ainfosec.com>
This commit is contained in:
Denny Sheirer
2026-11-05 07:38:17 -05:00
committed by GitHub
parent dea3a3a41e
commit d72c5d87be
62 changed files with 589 additions and 47 deletions

View File

@@ -0,0 +1,84 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2026 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.gui.control;
import javafx.collections.ListChangeListener;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import org.controlsfx.control.SegmentedButton;
/**
* Screen reader (accessibility) utilities for JavaFX controls.
*/
public final class AccessibilityUtil
{
private AccessibilityUtil()
{
//Not instantiable
}
/**
* Provides an accessible name for each toggle button in a segmented button group, combining the group label with
* the button text (e.g. "Channel Bandwidth: 12.5 kHz").
*
* A segmented button is a container, so a label can't identify it via Label.setLabelFor() in a way that screen
* readers announce: each toggle button receives focus individually and would otherwise be announced by its own text
* only, without the context of the group. Buttons added to the group later are also named.
*
* @param groupLabel that visually identifies the segmented button group
* @param segmentedButton containing the toggle buttons
*/
public static void labelGroup(Label groupLabel, SegmentedButton segmentedButton)
{
String groupName = groupLabel.getText() == null ? "" : groupLabel.getText().trim();
//Remove a trailing colon so that the name doesn't announce "colon colon"
if(groupName.endsWith(":"))
{
groupName = groupName.substring(0, groupName.length() - 1).trim();
}
final String name = groupName;
for(ToggleButton button: segmentedButton.getButtons())
{
setGroupName(name, button);
}
segmentedButton.getButtons().addListener((ListChangeListener<ToggleButton>)change -> {
while(change.next())
{
for(ToggleButton added: change.getAddedSubList())
{
setGroupName(name, added);
}
}
});
}
/**
* Sets the accessible text for the button as the group name and button text.
*/
private static void setGroupName(String groupName, ToggleButton button)
{
String text = button.getText() == null ? "" : button.getText();
button.setAccessibleText(groupName.isEmpty() ? text : groupName + ": " + text);
}
}

View File

@@ -0,0 +1,80 @@
/*
* *****************************************************************************
* Copyright (C) 2014-2026 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.gui.control;
import javafx.scene.AccessibleAction;
import javafx.scene.AccessibleAttribute;
import javafx.scene.AccessibleRole;
import org.controlsfx.control.ToggleSwitch;
/**
* ControlsFX toggle switch that exposes its role and on/off state to screen readers.
*
* The ControlsFX toggle switch doesn't provide an accessible role or selected state, so assistive technology sees it
* as a generic node with no state. This version reports itself as a toggle button, reports the selected state, and
* supports the accessible fire (toggle) action. The accessible name comes from the switch text, or from a label that
* identifies this switch via Label.setLabelFor().
*/
public class AccessibleToggleSwitch extends ToggleSwitch
{
/**
* Constructs an instance with no text. Use Label.setLabelFor() or setAccessibleText() to provide an accessible name.
*/
public AccessibleToggleSwitch()
{
this(null);
}
/**
* Constructs an instance
* @param text to display alongside the switch, also used as the accessible name.
*/
public AccessibleToggleSwitch(String text)
{
super(text);
setAccessibleRole(AccessibleRole.TOGGLE_BUTTON);
selectedProperty().addListener((observable, oldValue, newValue) ->
notifyAccessibleAttributeChanged(AccessibleAttribute.SELECTED));
}
@Override
public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters)
{
if(attribute == AccessibleAttribute.SELECTED)
{
return isSelected();
}
return super.queryAccessibleAttribute(attribute, parameters);
}
@Override
public void executeAccessibleAction(AccessibleAction action, Object... parameters)
{
if(action == AccessibleAction.FIRE)
{
fire();
}
else
{
super.executeAccessibleAction(action, parameters);
}
}
}

View File

@@ -21,6 +21,7 @@ package io.github.dsheirer.gui.playlist.alias;
import com.google.common.collect.Ordering;
import io.github.dsheirer.alias.Alias;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.icon.Icon;
import io.github.dsheirer.playlist.PlaylistManager;
@@ -100,6 +101,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(separator);
Label colorLabel = new Label("Color");
colorLabel.setLabelFor(getColorPicker());
GridPane.setHalignment(colorLabel, HPos.RIGHT);
GridPane.setConstraints(colorLabel, 0, ++row);
gridPane.getChildren().add(colorLabel);
@@ -114,6 +116,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getResetColorButton());
Label iconLabel = new Label("Icon");
iconLabel.setLabelFor(getIconNodeComboBox());
GridPane.setHalignment(iconLabel, HPos.RIGHT);
GridPane.setConstraints(iconLabel, 0, ++row);
gridPane.getChildren().add(iconLabel);
@@ -125,6 +128,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getApplyIconButton());
Label listenLabel = new Label("Listen");
listenLabel.setLabelFor(getMonitorAudioToggleSwitch());
GridPane.setHalignment(listenLabel, HPos.RIGHT);
GridPane.setConstraints(listenLabel, 0, ++row);
gridPane.getChildren().add(listenLabel);
@@ -133,6 +137,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getMonitorAudioToggleSwitch());
Label priorityLabel = new Label("Priority");
priorityLabel.setLabelFor(getMonitorPriorityComboBox());
GridPane.setHalignment(priorityLabel, HPos.RIGHT);
GridPane.setConstraints(priorityLabel, 2, row);
gridPane.getChildren().add(priorityLabel);
@@ -144,6 +149,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
gridPane.getChildren().add(getApplyMonitorButton());
Label recordLabel = new Label("Record");
recordLabel.setLabelFor(getRecordToggleSwitch());
GridPane.setHalignment(recordLabel, HPos.RIGHT);
GridPane.setConstraints(recordLabel, 0, ++row);
gridPane.getChildren().add(recordLabel);
@@ -235,6 +241,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyColorButton == null)
{
mApplyColorButton = new Button("Apply");
mApplyColorButton.setAccessibleText("Apply color to selected aliases");
mApplyColorButton.setOnAction(event ->
{
startChange();
@@ -258,6 +265,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mResetColorButton == null)
{
mResetColorButton = new Button("Reset Color");
mResetColorButton.setAccessibleText("Reset color for selected aliases");
mResetColorButton.setOnAction(event ->
{
startChange();
@@ -297,6 +305,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyIconButton == null)
{
mApplyIconButton = new Button("Apply");
mApplyIconButton.setAccessibleText("Apply icon to selected aliases");
mApplyIconButton.setDisable(true);
mApplyIconButton.setOnAction(new EventHandler<ActionEvent>()
{
@@ -327,7 +336,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
{
if(mMonitorAudioToggleSwitch == null)
{
mMonitorAudioToggleSwitch = new ToggleSwitch();
mMonitorAudioToggleSwitch = new AccessibleToggleSwitch();
mMonitorAudioToggleSwitch.setSelected(true);
mMonitorAudioToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -340,7 +349,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
{
if(mRecordToggleSwitch == null)
{
mRecordToggleSwitch = new ToggleSwitch();
mRecordToggleSwitch = new AccessibleToggleSwitch();
mRecordToggleSwitch.setSelected(false);
mRecordToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -374,6 +383,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyMonitorButton == null)
{
mApplyMonitorButton = new Button("Apply");
mApplyMonitorButton.setAccessibleText("Apply listen and priority to selected aliases");
mApplyMonitorButton.setOnAction(new EventHandler<ActionEvent>()
{
@Override
@@ -414,6 +424,7 @@ public class AliasBulkEditor extends Editor<List<Alias>>
if(mApplyRecordButton == null)
{
mApplyRecordButton = new Button("Apply");
mApplyRecordButton.setAccessibleText("Apply record to selected aliases");
mApplyRecordButton.setOnAction(event -> {
startChange();
boolean record = getRecordToggleSwitch().isSelected();
@@ -456,12 +467,15 @@ public class AliasBulkEditor extends Editor<List<Alias>>
{
setText(null);
setGraphic(null);
setAccessibleText(null);
}
else
{
textLabel.setText(item.getName());
iconLabel.setGraphic(new ImageView(item.getFxImage()));
setGraphic(gridPane);
//The name is shown in a nested label, so expose it as the cell's accessible text
setAccessibleText(item.getName());
}
}
};

View File

@@ -273,7 +273,9 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
Label listLabel = new Label("Alias List");
listLabel.setLabelFor(getAliasListNameComboBox());
Label searchLabel = new Label("Search");
searchLabel.setLabelFor(getSearchField());
searchLabel.setAlignment(Pos.CENTER_RIGHT);
HBox searchBox = new HBox();
@@ -451,6 +453,7 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
if(mAliasTableView == null)
{
mAliasTableView = new TableView<>();
mAliasTableView.setAccessibleText("Aliases");
TableColumn nameColumn = new TableColumn();
nameColumn.setText("Alias");
@@ -751,15 +754,18 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
UIManager.getColor("TextField.background"));
rectangle.setFill(ColorUtil.fromInteger(readable.equals(color) ? alias.getColor() :
readable.getRGB()));
setAccessibleText(String.format("#%06X", alias.getColor() & 0xFFFFFF));
}
else
{
rectangle.setVisible(false);
setAccessibleText(null);
}
}
else
{
rectangle.setVisible(false);
setAccessibleText(null);
}
}
};
@@ -798,13 +804,15 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
{
super.updateItem(item, empty);
if(!empty && getTableRow() != null)
if(!empty && getTableRow() != null && item != null)
{
iconNode.setVisible(item);
setAccessibleText(item ? "Yes" : "No");
}
else
{
iconNode.setVisible(false);
setAccessibleText(null);
}
}
};
@@ -919,6 +927,7 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
{
super.updateItem(item, empty);
setAlignment(Pos.CENTER);
setAccessibleText(null);
if(empty)
{
@@ -937,6 +946,7 @@ public class AliasConfigurationEditor extends SplitPane implements IAliasListRef
if(icon != null && icon.getFxImage() != null)
{
setGraphic(new ImageView(icon.getFxImage()));
setAccessibleText(icon.getName());
}
else
{

View File

@@ -57,6 +57,7 @@ import io.github.dsheirer.alias.id.talkgroup.TalkgroupRange;
import io.github.dsheirer.alias.id.tone.TonesID;
import io.github.dsheirer.audio.broadcast.ConfiguredBroadcast;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerFormatter;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.gui.playlist.alias.action.ActionEditor;
@@ -574,6 +575,7 @@ public class AliasItemEditor extends Editor<Alias>
{
mActionsList = new ListView<>(FXCollections.observableArrayList(AliasAction.extractor()));
mActionsList.setPrefHeight(75);
mActionsList.setAccessibleText("Alias actions");
mActionsList.setDisable(true);
mActionsList.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> setAction(newValue));
@@ -686,6 +688,7 @@ public class AliasItemEditor extends Editor<Alias>
mIdentifiersList = new ListView<>(FXCollections.observableArrayList(AliasID.extractor()));
mIdentifiersList.setDisable(true);
mIdentifiersList.setPrefHeight(75);
mIdentifiersList.setAccessibleText("Alias identifiers");
mIdentifiersList.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> setIdentifier(newValue));
mIdentifiersList.setCellFactory(param -> new AliasIdentifierCell());
@@ -846,13 +849,17 @@ public class AliasItemEditor extends Editor<Alias>
buttonBox.setSpacing(5);
buttonBox.getChildren().addAll(new Label(" "), getAddStreamButton(), getRemoveStreamButton());
Label availableLabel = new Label("Available");
getAvailableStreamsView().setAccessibleText("Available streams");
VBox availableBox = new VBox();
VBox.setVgrow(getAvailableStreamsView(), Priority.ALWAYS);
availableBox.getChildren().addAll(new Label("Available"), getAvailableStreamsView());
availableBox.getChildren().addAll(availableLabel, getAvailableStreamsView());
Label selectedLabel = new Label("Selected");
getSelectedStreamsView().setAccessibleText("Selected streams");
VBox selectedBox = new VBox();
VBox.setVgrow(getSelectedStreamsView(), Priority.ALWAYS);
selectedBox.getChildren().addAll(new Label("Selected"), getSelectedStreamsView());
selectedBox.getChildren().addAll(selectedLabel, getSelectedStreamsView());
HBox hbox = new HBox();
hbox.setSpacing(10);
@@ -864,6 +871,7 @@ public class AliasItemEditor extends Editor<Alias>
vbox.setSpacing(10);
VBox.setVgrow(hbox, Priority.ALWAYS);
Label label = new Label("Stream this Alias as Talkgroup:");
label.setLabelFor(getStreamAsTalkgroupField());
HBox streamAsHBox = new HBox();
streamAsHBox.setAlignment(Pos.CENTER_LEFT);
streamAsHBox.setSpacing(10);
@@ -964,6 +972,8 @@ public class AliasItemEditor extends Editor<Alias>
.or(Bindings.isNull(getAvailableStreamsView().getSelectionModel().selectedItemProperty())));
mAddStreamButton.setMaxWidth(Double.MAX_VALUE);
mAddStreamButton.setGraphic(new IconNode(FontAwesome.ANGLE_RIGHT));
mAddStreamButton.setAccessibleText("Add selected stream");
mAddStreamButton.setTooltip(new Tooltip("Add selected stream"));
mAddStreamButton.setAlignment(Pos.CENTER);
mAddStreamButton.setOnAction(event -> {
String stream = getAvailableStreamsView().getSelectionModel().getSelectedItem();
@@ -990,6 +1000,8 @@ public class AliasItemEditor extends Editor<Alias>
.or(Bindings.isNull(getSelectedStreamsView().getSelectionModel().selectedItemProperty())));
mRemoveStreamButton.setMaxWidth(Double.MAX_VALUE);
mRemoveStreamButton.setGraphic(new IconNode(FontAwesome.ANGLE_LEFT));
mRemoveStreamButton.setAccessibleText("Remove selected stream");
mRemoveStreamButton.setTooltip(new Tooltip("Remove selected stream"));
mRemoveStreamButton.setAlignment(Pos.CENTER);
mRemoveStreamButton.setOnAction(event -> {
BroadcastChannel broadcastChannel = getSelectedStreamsView().getSelectionModel().getSelectedItem();
@@ -1050,6 +1062,7 @@ public class AliasItemEditor extends Editor<Alias>
int row = 0;
Label nameLabel = new Label("Alias");
nameLabel.setLabelFor(getNameField());
GridPane.setHalignment(nameLabel, HPos.RIGHT);
GridPane.setConstraints(nameLabel, 0, row);
mTextFieldPane.getChildren().add(nameLabel);
@@ -1058,6 +1071,7 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getNameField());
Label monitorAudioLabel = new Label("Listen");
monitorAudioLabel.setLabelFor(getMonitorAudioToggleSwitch());
GridPane.setHalignment(monitorAudioLabel, HPos.RIGHT);
GridPane.setConstraints(monitorAudioLabel, 2, row);
mTextFieldPane.getChildren().add(monitorAudioLabel);
@@ -1065,6 +1079,7 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getMonitorAudioToggleSwitch());
Label monitorPriorityLabel = new Label("Priority");
monitorPriorityLabel.setLabelFor(getMonitorPriorityComboBox());
GridPane.setHalignment(monitorPriorityLabel, HPos.RIGHT);
GridPane.setConstraints(monitorPriorityLabel, 4, row);
mTextFieldPane.getChildren().add(monitorPriorityLabel);
@@ -1072,6 +1087,7 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getMonitorPriorityComboBox());
Label colorLabel = new Label("Color");
colorLabel.setLabelFor(getColorPicker());
GridPane.setHalignment(colorLabel, HPos.RIGHT);
GridPane.setConstraints(colorLabel, 6, row);
mTextFieldPane.getChildren().add(colorLabel);
@@ -1079,6 +1095,7 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getColorPicker());
Label groupLabel = new Label("Group");
groupLabel.setLabelFor(getGroupField());
GridPane.setHalignment(groupLabel, HPos.RIGHT);
GridPane.setConstraints(groupLabel, 0, ++row);
mTextFieldPane.getChildren().add(groupLabel);
@@ -1087,6 +1104,7 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getGroupField());
Label recordAudioLabel = new Label("Record");
recordAudioLabel.setLabelFor(getRecordAudioToggleSwitch());
GridPane.setHalignment(recordAudioLabel, HPos.RIGHT);
GridPane.setConstraints(recordAudioLabel, 2, row);
mTextFieldPane.getChildren().add(recordAudioLabel);
@@ -1094,6 +1112,7 @@ public class AliasItemEditor extends Editor<Alias>
mTextFieldPane.getChildren().add(getRecordAudioToggleSwitch());
Label iconLabel = new Label("Icon");
iconLabel.setLabelFor(getIconNodeComboBox());
GridPane.setHalignment(iconLabel, HPos.RIGHT);
GridPane.setConstraints(iconLabel, 4, row);
mTextFieldPane.getChildren().add(iconLabel);
@@ -1108,7 +1127,7 @@ public class AliasItemEditor extends Editor<Alias>
{
if(mMonitorAudioToggleSwitch == null)
{
mMonitorAudioToggleSwitch = new ToggleSwitch();
mMonitorAudioToggleSwitch = new AccessibleToggleSwitch();
mMonitorAudioToggleSwitch.setDisable(true);
mMonitorAudioToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -1141,7 +1160,7 @@ public class AliasItemEditor extends Editor<Alias>
{
if(mRecordAudioToggleSwitch == null)
{
mRecordAudioToggleSwitch = new ToggleSwitch();
mRecordAudioToggleSwitch = new AccessibleToggleSwitch();
mRecordAudioToggleSwitch.setDisable(true);
mRecordAudioToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -1820,12 +1839,15 @@ public class AliasItemEditor extends Editor<Alias>
{
setText(null);
setGraphic(null);
setAccessibleText(null);
}
else
{
textLabel.setText(item.getName());
iconLabel.setGraphic(new ImageView(item.getFxImage()));
setGraphic(gridPane);
//The name is shown in a nested label, so expose it as the cell's accessible text
setAccessibleText(item.getName());
}
}
};

View File

@@ -97,6 +97,7 @@ public class AliasViewByIdentifierEditor extends VBox
gridPane.setHgap(10);
Label aliasListLabel = new Label("Alias List");
aliasListLabel.setLabelFor(getAliasListNameComboBox());
GridPane.setHalignment(aliasListLabel, HPos.RIGHT);
GridPane.setConstraints(aliasListLabel, 0, 0);
gridPane.getChildren().add(aliasListLabel);
@@ -106,6 +107,7 @@ public class AliasViewByIdentifierEditor extends VBox
gridPane.getChildren().add(getAliasListNameComboBox());
Label identifierLabel = new Label("Identifier Type");
identifierLabel.setLabelFor(getAliasIDTypeComboBox());
GridPane.setHalignment(identifierLabel, HPos.RIGHT);
GridPane.setConstraints(identifierLabel, 0, 1);
gridPane.getChildren().add(identifierLabel);
@@ -210,6 +212,7 @@ public class AliasViewByIdentifierEditor extends VBox
if(mAliasAndIdentifierTableView == null)
{
mAliasAndIdentifierTableView = new TableView<>(FXCollections.observableArrayList(AliasAndIdentifier.extractor()));
mAliasAndIdentifierTableView.setAccessibleText("Aliases by identifier");
mAliasAndIdentifierTableView.setPlaceholder(new Label("No aliases or identifiers available"));
mIdentifierColumn = new TableColumn<>("Identifier");
mIdentifierColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getAliasIdentifier()));

View File

@@ -34,6 +34,7 @@ import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
@@ -157,12 +158,14 @@ public class AliasViewByRecordingEditor extends VBox
aliasListBox.setAlignment(Pos.CENTER);
aliasListBox.setSpacing(5);
Label aliasListLabel = new Label("Alias List");
aliasListLabel.setLabelFor(getAliasListNameComboBox());
aliasListBox.getChildren().addAll(aliasListLabel, getAliasListNameComboBox());
HBox searchBox = new HBox();
searchBox.setAlignment(Pos.CENTER);
searchBox.setSpacing(5);
Label searchLabel = new Label("Search");
searchLabel.setLabelFor(getSearchField());
searchBox.getChildren().addAll(searchLabel, getSearchField());
mTopBox.getChildren().addAll(aliasListBox, searchBox);
@@ -228,6 +231,7 @@ public class AliasViewByRecordingEditor extends VBox
if(mNoRecordAliasTableView == null)
{
mNoRecordAliasTableView = new TableView<>();
mNoRecordAliasTableView.setAccessibleText("Don't record audio aliases");
mNoRecordAliasTableView.setMaxHeight(Double.MAX_VALUE);
mNoRecordAliasTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@@ -266,6 +270,7 @@ public class AliasViewByRecordingEditor extends VBox
if(mRecordAliasTableView == null)
{
mRecordAliasTableView = new TableView<>();
mRecordAliasTableView.setAccessibleText("Record audio aliases");
mRecordAliasTableView.setMaxHeight(Double.MAX_VALUE);
mRecordAliasTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@@ -307,6 +312,8 @@ public class AliasViewByRecordingEditor extends VBox
mAddButton.setDisable(true);
mAddButton.setMaxWidth(Double.MAX_VALUE);
mAddButton.setGraphic(new IconNode(FontAwesome.ANGLE_RIGHT));
mAddButton.setAccessibleText("Record audio for selected alias");
mAddButton.setTooltip(new Tooltip("Record audio for selected alias"));
mAddButton.setAlignment(Pos.CENTER);
mAddButton.setOnAction(event -> {
Alias selectedAlias = getNoRecordAliasTableView().getSelectionModel().getSelectedItem();
@@ -330,6 +337,8 @@ public class AliasViewByRecordingEditor extends VBox
mAddAllButton.setDisable(true);
mAddAllButton.setMaxWidth(Double.MAX_VALUE);
mAddAllButton.setGraphic(new IconNode(FontAwesome.ANGLE_DOUBLE_RIGHT));
mAddAllButton.setAccessibleText("Record audio for all selected aliases");
mAddAllButton.setTooltip(new Tooltip("Record audio for all selected aliases"));
mAddAllButton.setAlignment(Pos.CENTER);
mAddAllButton.setOnAction(event -> {
List<Alias> selectedAliases =
@@ -358,6 +367,8 @@ public class AliasViewByRecordingEditor extends VBox
mRemoveButton.setDisable(true);
mRemoveButton.setMaxWidth(Double.MAX_VALUE);
mRemoveButton.setGraphic(new IconNode(FontAwesome.ANGLE_LEFT));
mRemoveButton.setAccessibleText("Don't record audio for selected alias");
mRemoveButton.setTooltip(new Tooltip("Don't record audio for selected alias"));
mRemoveButton.setAlignment(Pos.CENTER);
mRemoveButton.setOnAction(event -> {
Alias selectedAlias = getRecordAliasTableView().getSelectionModel().getSelectedItem();
@@ -381,6 +392,8 @@ public class AliasViewByRecordingEditor extends VBox
mRemoveAllButton.setDisable(true);
mRemoveAllButton.setMaxWidth(Double.MAX_VALUE);
mRemoveAllButton.setGraphic(new IconNode(FontAwesome.ANGLE_DOUBLE_LEFT));
mRemoveAllButton.setAccessibleText("Don't record audio for all selected aliases");
mRemoveAllButton.setTooltip(new Tooltip("Don't record audio for all selected aliases"));
mRemoveAllButton.setAlignment(Pos.CENTER);
mRemoveAllButton.setOnAction(event -> {
List<Alias> selectedAliases =

View File

@@ -66,6 +66,7 @@ public class BeepEditor extends ActionEditor<BeepAction>
int row = 0;
Label intervalLabel = new Label(("Beep"));
intervalLabel.setLabelFor(getIntervalComboBox());
GridPane.setHalignment(intervalLabel, HPos.RIGHT);
GridPane.setConstraints(intervalLabel, 0, row);
gridPane.getChildren().add(intervalLabel);
@@ -80,6 +81,7 @@ public class BeepEditor extends ActionEditor<BeepAction>
GridPane.setConstraints(getSecondsLabel(), 3, row);
GridPane.setHgrow(getSecondsLabel(), Priority.ALWAYS);
gridPane.getChildren().add(getSecondsLabel());
getSecondsLabel().setLabelFor(getPeriodTextField());
GridPane.setConstraints(getTestButton(), 4, row);
gridPane.getChildren().add(getTestButton());
@@ -155,6 +157,7 @@ public class BeepEditor extends ActionEditor<BeepAction>
if(mTestButton == null)
{
mTestButton = new Button("Test");
mTestButton.setAccessibleText("Test beep");
mTestButton.setMaxWidth(Double.MAX_VALUE);
mTestButton.setOnAction(event -> test());
}

View File

@@ -71,6 +71,7 @@ public class ClipEditor extends ActionEditor<ClipAction>
int row = 0;
Label fileLabel = new Label("Audio File");
fileLabel.setLabelFor(getFilePath());
GridPane.setHalignment(fileLabel, HPos.RIGHT);
GridPane.setConstraints(fileLabel, 0, row);
gridPane.getChildren().add(fileLabel);
@@ -83,6 +84,7 @@ public class ClipEditor extends ActionEditor<ClipAction>
gridPane.getChildren().add(getFileChooser());
Label intervalLabel = new Label(("Play Audio Clip"));
intervalLabel.setLabelFor(getIntervalComboBox());
GridPane.setHalignment(intervalLabel, HPos.RIGHT);
GridPane.setConstraints(intervalLabel, 0, ++row);
gridPane.getChildren().add(intervalLabel);
@@ -97,6 +99,7 @@ public class ClipEditor extends ActionEditor<ClipAction>
GridPane.setConstraints(getSecondsLabel(), 3, row);
GridPane.setHgrow(getSecondsLabel(), Priority.ALWAYS);
gridPane.getChildren().add(getSecondsLabel());
getSecondsLabel().setLabelFor(getPeriodTextField());
GridPane.setConstraints(getTestButton(), 4, row);
gridPane.getChildren().add(getTestButton());
@@ -223,6 +226,7 @@ public class ClipEditor extends ActionEditor<ClipAction>
if(mTestButton == null)
{
mTestButton = new Button("Test");
mTestButton.setAccessibleText("Test audio clip");
mTestButton.setMaxWidth(Double.MAX_VALUE);
mTestButton.setDisable(true);
mTestButton.setOnAction(event -> test());
@@ -236,6 +240,7 @@ public class ClipEditor extends ActionEditor<ClipAction>
if(mFileChooser == null)
{
mFileChooser = new Button(("Select ..."));
mFileChooser.setAccessibleText("Select audio file");
mFileChooser.setMaxWidth(Double.MAX_VALUE);
mFileChooser.setDisable(true);
mFileChooser.setOnAction(event -> {
@@ -278,7 +283,8 @@ public class ClipEditor extends ActionEditor<ClipAction>
if(mFilePath == null)
{
mFilePath = new TextField(PLEASE_SELECT_A_FILE);
mFilePath.setDisable(true);
//Read-only rather than disabled so that the selected file remains focusable for screen readers
mFilePath.setEditable(false);
mFilePath.setMaxWidth(Double.MAX_VALUE);
mFilePath.textProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null && !newValue.isEmpty() && !newValue.contentEquals(PLEASE_SELECT_A_FILE))

View File

@@ -71,6 +71,7 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
int row = 0;
Label fileLabel = new Label("Script File");
fileLabel.setLabelFor(getFilePath());
GridPane.setHalignment(fileLabel, HPos.RIGHT);
GridPane.setConstraints(fileLabel, 0, row);
gridPane.getChildren().add(fileLabel);
@@ -83,6 +84,7 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
gridPane.getChildren().add(getFileChooser());
Label intervalLabel = new Label(("Run Script"));
intervalLabel.setLabelFor(getIntervalComboBox());
GridPane.setHalignment(intervalLabel, HPos.RIGHT);
GridPane.setConstraints(intervalLabel, 0, ++row);
gridPane.getChildren().add(intervalLabel);
@@ -97,6 +99,7 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
GridPane.setConstraints(getSecondsLabel(), 3, row);
GridPane.setHgrow(getSecondsLabel(), Priority.ALWAYS);
gridPane.getChildren().add(getSecondsLabel());
getSecondsLabel().setLabelFor(getPeriodTextField());
GridPane.setConstraints(getTestButton(), 4, row);
gridPane.getChildren().add(getTestButton());
@@ -223,6 +226,7 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
if(mTestButton == null)
{
mTestButton = new Button("Test");
mTestButton.setAccessibleText("Test script");
mTestButton.setMaxWidth(Double.MAX_VALUE);
mTestButton.setDisable(true);
mTestButton.setOnAction(event -> test());
@@ -236,6 +240,7 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
if(mFileChooser == null)
{
mFileChooser = new Button(("Select ..."));
mFileChooser.setAccessibleText("Select script file");
mFileChooser.setMaxWidth(Double.MAX_VALUE);
mFileChooser.setDisable(true);
mFileChooser.setOnAction(event -> {
@@ -278,7 +283,8 @@ public class ScriptEditor extends ActionEditor<ScriptAction>
if(mFilePath == null)
{
mFilePath = new TextField(PLEASE_SELECT_A_FILE);
mFilePath.setDisable(true);
//Read-only rather than disabled so that the selected file remains focusable for screen readers
mFilePath.setEditable(false);
mFilePath.setMaxWidth(Double.MAX_VALUE);
mFilePath.textProperty().addListener((observable, oldValue, newValue) -> {
if(newValue != null && !newValue.isEmpty() && !newValue.contentEquals(PLEASE_SELECT_A_FILE))

View File

@@ -44,6 +44,7 @@ public class DcsEditor extends IdentifierEditor<Dcs>
gridPane.setHgap(5);
Label typeLabel = new Label("DCS Code");
typeLabel.setLabelFor(getDCSCodeComboBox());
GridPane.setConstraints(typeLabel, 0, 0);
gridPane.getChildren().add(typeLabel);

View File

@@ -54,6 +54,7 @@ public class EsnEditor extends IdentifierEditor<Esn>
gridPane.setHgap(5);
Label typeLabel = new Label("ESN");
typeLabel.setLabelFor(getEsnField());
GridPane.setConstraints(typeLabel, 0, 0);
gridPane.getChildren().add(typeLabel);

View File

@@ -47,6 +47,7 @@ public class LojackEditor extends IdentifierEditor<LoJackFunctionAndID>
gridPane.setHgap(5);
Label typeLabel = new Label("LoJack Function");
typeLabel.setLabelFor(getFunctionComboBox());
GridPane.setConstraints(typeLabel, 0, 0);
gridPane.getChildren().add(typeLabel);
@@ -57,6 +58,10 @@ public class LojackEditor extends IdentifierEditor<LoJackFunctionAndID>
gridPane.getChildren().add(getIdentifierField());
Label helpLabel = new Label("Format: 5 numbers, characters or (*)wildcard - e.g. AB*12");
//The identifier field has no label of its own, so the help label provides its accessible name and help text
helpLabel.setLabelFor(getIdentifierField());
helpLabel.setAccessibleText("LoJack ID");
getIdentifierField().setAccessibleHelp(helpLabel.getText());
GridPane.setConstraints(helpLabel, 3, 0);
gridPane.getChildren().add(helpLabel);

View File

@@ -76,11 +76,13 @@ public class NXDNTypeDEditor<T extends AliasID & INXDNTypeD> extends IdentifierE
gridPane.add(new Label("NXDN Type-D"), 0, 0);
Label homeRepeaterLabel = new Label("Home Repeater");
homeRepeaterLabel.setLabelFor(mHomeRepeaterField);
GridPane.setHalignment(homeRepeaterLabel, HPos.RIGHT);
gridPane.add(homeRepeaterLabel, 1, 0);
gridPane.add(mHomeRepeaterField, 2, 0);
Label identifierFieldLabel = new Label(identifierLabel);
identifierFieldLabel.setLabelFor(mIdentifierField);
GridPane.setHalignment(identifierFieldLabel, HPos.RIGHT);
gridPane.add(identifierFieldLabel, 3, 0);
gridPane.add(mIdentifierField, 4, 0);

View File

@@ -89,15 +89,21 @@ public class NXDNTypeDRangeEditor<T extends AliasID & INXDNTypeDRange> extends I
gridPane.add(new Label("NXDN Type-D"), 0, 0);
Label homeRepeaterLabel = new Label("Home Repeater");
homeRepeaterLabel.setLabelFor(mHomeRepeaterField);
GridPane.setHalignment(homeRepeaterLabel, HPos.RIGHT);
gridPane.add(homeRepeaterLabel, 1, 0);
gridPane.add(mHomeRepeaterField, 2, 0);
Label rangeFieldLabel = new Label(rangeLabel);
rangeFieldLabel.setLabelFor(mMinField);
rangeFieldLabel.setAccessibleText(rangeLabel + " start");
GridPane.setHalignment(rangeFieldLabel, HPos.RIGHT);
gridPane.add(rangeFieldLabel, 3, 0);
gridPane.add(mMinField, 4, 0);
gridPane.add(new Label("-"), 5, 0);
Label dashLabel = new Label("-");
dashLabel.setLabelFor(mMaxField);
dashLabel.setAccessibleText(rangeLabel + " end");
gridPane.add(dashLabel, 5, 0);
gridPane.add(mMaxField, 6, 0);
getChildren().add(gridPane);

View File

@@ -70,6 +70,7 @@ public class P25FullyQualifiedRadioIdEditor extends IdentifierEditor<P25FullyQua
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("WACN");
valueLabel.setLabelFor(getWacnField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -78,6 +79,7 @@ public class P25FullyQualifiedRadioIdEditor extends IdentifierEditor<P25FullyQua
gridPane.getChildren().add(getWacnField());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 3, 0);
gridPane.getChildren().add(systemLabel);
@@ -86,6 +88,7 @@ public class P25FullyQualifiedRadioIdEditor extends IdentifierEditor<P25FullyQua
gridPane.getChildren().add(getSystemField());
Label radioLabel = new Label("Radio ID");
radioLabel.setLabelFor(getRadioField());
GridPane.setHalignment(radioLabel, HPos.RIGHT);
GridPane.setConstraints(radioLabel, 5, 0);
gridPane.getChildren().add(radioLabel);

View File

@@ -70,6 +70,7 @@ public class P25FullyQualifiedTalkgroupEditor extends IdentifierEditor<P25FullyQ
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("WACN");
valueLabel.setLabelFor(getWacnField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -78,6 +79,7 @@ public class P25FullyQualifiedTalkgroupEditor extends IdentifierEditor<P25FullyQ
gridPane.getChildren().add(getWacnField());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 3, 0);
gridPane.getChildren().add(systemLabel);
@@ -86,6 +88,7 @@ public class P25FullyQualifiedTalkgroupEditor extends IdentifierEditor<P25FullyQ
gridPane.getChildren().add(getSystemField());
Label radioLabel = new Label("Talkgroup");
radioLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(radioLabel, HPos.RIGHT);
GridPane.setConstraints(radioLabel, 5, 0);
gridPane.getChildren().add(radioLabel);

View File

@@ -71,6 +71,7 @@ public class RadioIdEditor extends IdentifierEditor<Radio>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Radio ID");
valueLabel.setLabelFor(getRadioIdField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -73,6 +73,8 @@ public class RadioIdRangeEditor extends IdentifierEditor<RadioRange>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Radio ID Range");
valueLabel.setLabelFor(getMinRadioIdField());
valueLabel.setAccessibleText("Radio ID Range start");
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -81,6 +83,8 @@ public class RadioIdRangeEditor extends IdentifierEditor<RadioRange>
gridPane.getChildren().add(getMinRadioIdField());
Label dashLabel = new Label("-");
dashLabel.setLabelFor(getMaxRadioIdField());
dashLabel.setAccessibleText("Radio ID Range end");
GridPane.setConstraints(dashLabel, 3, 0);
gridPane.getChildren().add(dashLabel);

View File

@@ -73,6 +73,7 @@ public class TalkgroupEditor extends IdentifierEditor<Talkgroup>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Talkgroup");
valueLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -75,6 +75,8 @@ public class TalkgroupRangeEditor extends IdentifierEditor<TalkgroupRange>
gridPane.getChildren().add(getProtocolLabel());
Label valueLabel = new Label("Talkgroup Range");
valueLabel.setLabelFor(getMinTalkgroupField());
valueLabel.setAccessibleText("Talkgroup Range start");
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 1, 0);
gridPane.getChildren().add(valueLabel);
@@ -83,6 +85,8 @@ public class TalkgroupRangeEditor extends IdentifierEditor<TalkgroupRange>
gridPane.getChildren().add(getMinTalkgroupField());
Label dashLabel = new Label("-");
dashLabel.setLabelFor(getMaxTalkgroupField());
dashLabel.setAccessibleText("Talkgroup Range end");
GridPane.setConstraints(dashLabel, 3, 0);
gridPane.getChildren().add(dashLabel);

View File

@@ -73,6 +73,7 @@ public class TonesEditor extends IdentifierEditor<TonesID>
editorsPane.setVgap(10);
Label toneLabel = new Label("Tone");
toneLabel.setLabelFor(getAmbeToneComboBox());
GridPane.setConstraints(toneLabel, 0, 0);
GridPane.setHalignment(toneLabel, HPos.RIGHT);
editorsPane.getChildren().add(toneLabel);
@@ -81,6 +82,7 @@ public class TonesEditor extends IdentifierEditor<TonesID>
editorsPane.getChildren().add(getAmbeToneComboBox());
Label durationLabel = new Label("Duration 1-50");
durationLabel.setLabelFor(getDurationTextField());
GridPane.setConstraints(durationLabel, 0, 1);
GridPane.setHalignment(durationLabel, HPos.RIGHT);
editorsPane.getChildren().add(durationLabel);
@@ -222,6 +224,7 @@ public class TonesEditor extends IdentifierEditor<TonesID>
iconNode.setIconSize(12);
iconNode.setFill(getMoveUpButton().getTextFill());
mMoveUpButton.setGraphic(iconNode);
mMoveUpButton.setAccessibleText("Move tone up");
mMoveUpButton.setMaxWidth(Double.MAX_VALUE);
mMoveUpButton.setDisable(true);
mMoveUpButton.setOnAction(event -> {
@@ -249,6 +252,7 @@ public class TonesEditor extends IdentifierEditor<TonesID>
iconNode.setIconSize(12);
iconNode.setFill(getMoveDownButton().getTextFill());
mMoveDownButton.setGraphic(iconNode);
mMoveDownButton.setAccessibleText("Move tone down");
mMoveDownButton.setMaxWidth(Double.MAX_VALUE);
mMoveDownButton.setDisable(true);
mMoveDownButton.setOnAction(event -> {
@@ -274,6 +278,7 @@ public class TonesEditor extends IdentifierEditor<TonesID>
mToneListView = new ListView<>();
mToneListView.setDisable(true);
mToneListView.setPrefHeight(75);
mToneListView.setAccessibleText("Tone sequence");
mToneListView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
setTone(newValue);
});

View File

@@ -58,6 +58,7 @@ public class UnitStatusEditor extends IdentifierEditor<UnitStatusID>
gridPane.setVgap(3);
Label valueLabel = new Label("Unit Status");
valueLabel.setLabelFor(getUnitStatusField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 0, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -51,6 +51,7 @@ public class UserStatusEditor extends IdentifierEditor<UserStatusID>
gridPane.setVgap(3);
Label valueLabel = new Label("User Status");
valueLabel.setLabelFor(getUserStatusField());
GridPane.setHalignment(valueLabel, HPos.RIGHT);
GridPane.setConstraints(valueLabel, 0, 0);
gridPane.getChildren().add(valueLabel);

View File

@@ -19,6 +19,8 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.DbPowerMeter;
import io.github.dsheirer.gui.control.HexFormatter;
import io.github.dsheirer.gui.control.IntegerFormatter;
@@ -134,6 +136,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label bandwidthLabel = new Label("Channel Bandwidth");
AccessibilityUtil.labelGroup(bandwidthLabel, getBandwidthButton());
GridPane.setHalignment(bandwidthLabel, HPos.RIGHT);
GridPane.setConstraints(bandwidthLabel, 0, row);
gridPane.getChildren().add(bandwidthLabel);
@@ -142,6 +145,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getBandwidthButton());
Label squelchLabel = new Label("Squelch Threshold");
squelchLabel.setLabelFor(getSquelchThresholdField());
GridPane.setHalignment(squelchLabel, HPos.RIGHT);
GridPane.setConstraints(squelchLabel, 0, row);
gridPane.getChildren().add(squelchLabel);
@@ -150,6 +154,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getSquelchThresholdField());
Label autoTrackLabel = new Label("Squelch Auto-Track");
autoTrackLabel.setLabelFor(getSquelchAutoTrackSwitch());
GridPane.setHalignment(autoTrackLabel, HPos.RIGHT);
GridPane.setConstraints(autoTrackLabel, 2, row);
gridPane.getChildren().add(autoTrackLabel);
@@ -159,6 +164,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getSquelchAutoTrackSwitch());
Label talkgroupLabel = new Label("Talkgroup To Assign");
talkgroupLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(talkgroupLabel, HPos.RIGHT);
GridPane.setConstraints(talkgroupLabel, 4, row);
gridPane.getChildren().add(talkgroupLabel);
@@ -210,6 +216,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getBasebandRecordSwitch());
Label recordBasebandLabel = new Label("Channel (Baseband I&Q)");
recordBasebandLabel.setLabelFor(getBasebandRecordSwitch());
GridPane.setHalignment(recordBasebandLabel, HPos.LEFT);
GridPane.setConstraints(recordBasebandLabel, 1, 1);
gridPane.getChildren().add(recordBasebandLabel);
@@ -254,7 +261,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
{
if(mBasebandRecordSwitch == null)
{
mBasebandRecordSwitch = new ToggleSwitch();
mBasebandRecordSwitch = new AccessibleToggleSwitch();
mBasebandRecordSwitch.setDisable(true);
mBasebandRecordSwitch.setTextAlignment(TextAlignment.RIGHT);
mBasebandRecordSwitch.selectedProperty()
@@ -348,7 +355,7 @@ public class AMConfigurationEditor extends ChannelConfigurationEditor
{
if(mSquelchAutoTrackSwitch == null)
{
mSquelchAutoTrackSwitch = new ToggleSwitch();
mSquelchAutoTrackSwitch = new AccessibleToggleSwitch();
mSquelchAutoTrackSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -23,6 +23,7 @@ import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.controller.channel.ChannelException;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.MaxLengthUnaryOperator;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.gui.preference.PreferenceEditorType;
@@ -464,7 +465,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
{
if(mAutoStartSwitch == null)
{
mAutoStartSwitch = new ToggleSwitch();
mAutoStartSwitch = new AccessibleToggleSwitch();
mAutoStartSwitch.setDisable(true);
mAutoStartSwitch.setDisable(true);
mAutoStartSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -533,6 +534,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
int row = 0;
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, row);
mTextFieldPane.getChildren().add(systemLabel);
@@ -542,6 +544,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getSystemField());
Label autoStartLabel = new Label("Auto-Start");
autoStartLabel.setLabelFor(getAutoStartSwitch());
GridPane.setHalignment(autoStartLabel, HPos.RIGHT);
GridPane.setConstraints(autoStartLabel, 2, row);
mTextFieldPane.getChildren().add(autoStartLabel);
@@ -554,6 +557,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getPlayButton());
Label siteLabel = new Label("Site");
siteLabel.setLabelFor(getSiteField());
GridPane.setHalignment(siteLabel, HPos.RIGHT);
GridPane.setConstraints(siteLabel, 0, ++row);
mTextFieldPane.getChildren().add(siteLabel);
@@ -563,6 +567,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getSiteField());
Label autoStartOrderLabel = new Label("Start Order");
autoStartOrderLabel.setLabelFor(getAutoStartOrderSpinner());
GridPane.setHalignment(autoStartOrderLabel, HPos.RIGHT);
GridPane.setConstraints(autoStartOrderLabel, 2, row);
mTextFieldPane.getChildren().add(autoStartOrderLabel);
@@ -572,6 +577,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getAutoStartOrderSpinner());
Label nameLabel = new Label("Name");
nameLabel.setLabelFor(getNameField());
GridPane.setHalignment(nameLabel, HPos.RIGHT);
GridPane.setConstraints(nameLabel, 0, ++row);
mTextFieldPane.getChildren().add(nameLabel);
@@ -581,6 +587,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
mTextFieldPane.getChildren().add(getNameField());
Label aliasListLabel = new Label("Alias List");
aliasListLabel.setLabelFor(getAliasListComboBox());
GridPane.setHalignment(aliasListLabel, HPos.RIGHT);
GridPane.setConstraints(aliasListLabel, 2, row);
mTextFieldPane.getChildren().add(aliasListLabel);
@@ -708,20 +715,25 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
audioPane.add(new Label(title), 0, 0);
Label noiseGainLabel = new Label("Comfort Noise Volume:");
noiseGainLabel.setLabelFor(noiseGainSlider);
GridPane.setHalignment(noiseGainLabel, HPos.RIGHT);
audioPane.add(noiseGainLabel, 1, 0);
audioPane.add(createSliderWithReset(noiseGainSlider, DecodeConfigJMBE.DEFAULT_COMFORT_NOISE_GAIN), 2, 0);
audioPane.add(createSliderWithReset(noiseGainSlider, DecodeConfigJMBE.DEFAULT_COMFORT_NOISE_GAIN,
"Reset comfort noise volume"), 2, 0);
Label agcLabel = new Label("AGC:");
agcLabel.setLabelFor(agcSwitch);
agcLabel.setTooltip(agcSwitch.getTooltip());
GridPane.setHalignment(agcLabel, HPos.RIGHT);
audioPane.add(agcLabel, 3, 0);
audioPane.add(agcSwitch, 4, 0);
Label toneGainLabel = new Label("Tone Volume:");
toneGainLabel.setLabelFor(toneGainSlider);
GridPane.setHalignment(toneGainLabel, HPos.RIGHT);
audioPane.add(toneGainLabel, 1, 1);
audioPane.add(createSliderWithReset(toneGainSlider, DecodeConfigJMBE.DEFAULT_TONE_GAIN), 2, 1);
audioPane.add(createSliderWithReset(toneGainSlider, DecodeConfigJMBE.DEFAULT_TONE_GAIN, "Reset tone volume"), 2, 1);
Label legacyToneLevelsLabel = new Label("Use Legacy Tone Levels:");
legacyToneLevelsLabel.setLabelFor(legacyToneLevelsSwitch);
legacyToneLevelsLabel.setTooltip(legacyToneLevelsSwitch.getTooltip());
GridPane.setHalignment(legacyToneLevelsLabel, HPos.RIGHT);
audioPane.add(legacyToneLevelsLabel, 3, 1);
@@ -739,9 +751,10 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
* current slider value and a small reset button. The label and button track the disabled state of the slider.
* @param slider to wrap
* @param defaultValue to apply to the slider when the reset button is clicked
* @param resetName accessible name for the reset button, announced by screen readers
* @return box containing the slider, the value label and the reset button
*/
private HBox createSliderWithReset(Slider slider, double defaultValue)
private HBox createSliderWithReset(Slider slider, double defaultValue, String resetName)
{
IconNode resetIcon = new IconNode(FontAwesome.UNDO);
resetIcon.setIconSize(10);
@@ -750,6 +763,7 @@ public abstract class ChannelConfigurationEditor extends Editor<Channel>
resetIcon.fillProperty().bind(resetButton.textFillProperty());
resetButton.setGraphic(resetIcon);
resetButton.setTooltip(new Tooltip("Reset to default value"));
resetButton.setAccessibleText(resetName);
resetButton.disableProperty().bind(slider.disableProperty());
resetButton.setOnAction(event -> slider.setValue(defaultValue));

View File

@@ -21,6 +21,7 @@ package io.github.dsheirer.gui.playlist.channel;
import com.google.common.base.Joiner;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.playlist.IAliasListRefreshListener;
import io.github.dsheirer.module.decode.DecoderFactory;
import io.github.dsheirer.module.decode.DecoderType;
@@ -336,6 +337,7 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
searchBox.setSpacing(5);
searchBox.setAlignment(Pos.CENTER);
Label searchLabel = new Label("Search:");
searchLabel.setLabelFor(getSearchField());
searchLabel.setAlignment(Pos.CENTER_RIGHT);
searchBox.getChildren().addAll(searchLabel, getSearchField());
@@ -343,6 +345,7 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
viewBox.setSpacing(5);
viewBox.setAlignment(Pos.CENTER);
Label viewLabel = new Label("View Channels:");
AccessibilityUtil.labelGroup(viewLabel, getViewSegmentedButton());
viewBox.getChildren().addAll(viewLabel, getViewSegmentedButton());
mSearchAndViewBox.getChildren().addAll(searchBox, viewBox);
@@ -409,6 +412,7 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
if(mChannelTableView == null)
{
mChannelTableView = new TableView<>();
mChannelTableView.setAccessibleText("Channels");
TableColumn<Channel,Boolean> playingColumn = new TableColumn("Playing");
playingColumn.setPrefWidth(75);
@@ -425,12 +429,14 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
if(empty || item == null || !item)
{
setGraphic(null);
setAccessibleText(empty ? null : "No");
}
else
{
IconNode iconNode = new IconNode(FontAwesome.CHECK);
iconNode.setFill(Color.GREEN);
setGraphic(iconNode);
setAccessibleText("Yes");
}
}
};
@@ -453,12 +459,14 @@ public class ChannelEditor extends SplitPane implements IFilterProcessor, IAlias
if(empty || item == null || !item)
{
setGraphic(null);
setAccessibleText(empty ? null : "No");
}
else
{
IconNode iconNode = new IconNode(FontAwesome.CHECK);
iconNode.setFill(Color.GREEN);
setGraphic(iconNode);
setAccessibleText("Yes");
}
}
};

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -142,6 +143,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 0, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -153,6 +155,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreDataCallsButton());
Label ignoreDataLabel = new Label("Ignore Data Calls");
ignoreDataLabel.setLabelFor(getIgnoreDataCallsButton());
GridPane.setHalignment(ignoreDataLabel, HPos.LEFT);
GridPane.setConstraints(ignoreDataLabel, 3, row);
gridPane.getChildren().add(ignoreDataLabel);
@@ -161,6 +164,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreCRCChecksumsButton());
Label ignoreCRCLabel = new Label("Ignore CRC Checksums (RAS)");
ignoreCRCLabel.setLabelFor(getIgnoreCRCChecksumsButton());
GridPane.setHalignment(ignoreCRCLabel, HPos.LEFT);
GridPane.setConstraints(ignoreCRCLabel, 5, row);
gridPane.getChildren().add(ignoreCRCLabel);
@@ -169,6 +173,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getUseCompressedTalkgroupsToggle());
Label useCompressedTalkgroupsLabel = new Label("Use Compressed Talkgroups");
useCompressedTalkgroupsLabel.setLabelFor(getUseCompressedTalkgroupsToggle());
GridPane.setHalignment(useCompressedTalkgroupsLabel, HPos.LEFT);
GridPane.setConstraints(useCompressedTalkgroupsLabel, 7, row);
gridPane.getChildren().add(useCompressedTalkgroupsLabel);
@@ -196,9 +201,11 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
editorBox.setSpacing(5);
Label lcnLabel = new Label("LCN");
lcnLabel.setLabelFor(getLogicalChannelNumberField());
editorBox.getChildren().addAll(lcnLabel, getLogicalChannelNumberField());
Label downlinkLabel = new Label("Frequency (MHz)");
downlinkLabel.setLabelFor(getDownlinkFrequencyField());
downlinkLabel.setPadding(new Insets(0,0,0,5));
editorBox.getChildren().addAll(downlinkLabel,getDownlinkFrequencyField());
@@ -286,6 +293,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
if(mTimeslotFrequencyTable == null)
{
mTimeslotFrequencyTable = new TableView<>(FXCollections.observableArrayList(TimeslotFrequency.extractor()));
mTimeslotFrequencyTable.setAccessibleText("Logical channel number (LCN) to frequency map");
mTimeslotFrequencyTable.setPrefHeight(100.0);
TableColumn<TimeslotFrequency,Number> numberColumn = new TableColumn("LCN");
@@ -346,6 +354,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
if(mAddTimeslotFrequencyButton == null)
{
mAddTimeslotFrequencyButton = new Button("Add");
mAddTimeslotFrequencyButton.setAccessibleText("Add LCN frequency");
mAddTimeslotFrequencyButton.setMaxWidth(Double.MAX_VALUE);
mAddTimeslotFrequencyButton.setOnAction(event -> addTimeslot());
}
@@ -394,6 +403,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
if(mDeleteTimeslotFrequencyButton == null)
{
mDeleteTimeslotFrequencyButton = new Button("Delete");
mDeleteTimeslotFrequencyButton.setAccessibleText("Delete LCN frequency");
mDeleteTimeslotFrequencyButton.setDisable(true);
mDeleteTimeslotFrequencyButton.setMaxWidth(Double.MAX_VALUE);
mDeleteTimeslotFrequencyButton.setOnAction(new EventHandler<ActionEvent>()
@@ -501,7 +511,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsButton == null)
{
mIgnoreDataCallsButton = new ToggleSwitch();
mIgnoreDataCallsButton = new AccessibleToggleSwitch();
mIgnoreDataCallsButton.setDisable(true);
mIgnoreDataCallsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -514,7 +524,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreCRCChecksumsButton == null)
{
mIgnoreCRCChecksumsButton = new ToggleSwitch();
mIgnoreCRCChecksumsButton = new AccessibleToggleSwitch();
mIgnoreCRCChecksumsButton.setDisable(true);
mIgnoreCRCChecksumsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -532,7 +542,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mUseCompressedTalkgroupsToggle == null)
{
mUseCompressedTalkgroupsToggle = new ToggleSwitch();
mUseCompressedTalkgroupsToggle = new AccessibleToggleSwitch();
mUseCompressedTalkgroupsToggle.setTooltip(new Tooltip("Use Compressed Talkgroups. This is only for Hytera Tier-III Trunked Systems"));
mUseCompressedTalkgroupsToggle.setDisable(true);
mUseCompressedTalkgroupsToggle.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
@@ -563,7 +573,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -576,7 +586,7 @@ public class DMRConfigurationEditor extends ChannelConfigurationEditor
{
if(mLegacyToneLevelsButton == null)
{
mLegacyToneLevelsButton = new ToggleSwitch();
mLegacyToneLevelsButton = new AccessibleToggleSwitch();
mLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.playlist.decoder.AuxDecoderConfigurationEditor;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -146,6 +147,7 @@ public class LTRConfigurationEditor extends ChannelConfigurationEditor
gridPane.setHgap(10);
Label directionLabel = new Label("Direction");
AccessibilityUtil.labelGroup(directionLabel, getDirectionButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 0, 0);
gridPane.getChildren().add(directionLabel);

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.playlist.decoder.AuxDecoderConfigurationEditor;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -146,6 +147,7 @@ public class LTRNetConfigurationEditor extends ChannelConfigurationEditor
gridPane.setHgap(10);
Label directionLabel = new Label("Direction");
AccessibilityUtil.labelGroup(directionLabel, getDirectionButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 0, 0);
gridPane.getChildren().add(directionLabel);

View File

@@ -126,6 +126,7 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
gridPane.setVgap(10);
Label channelMapLabel = new Label("Channel Map");
channelMapLabel.setLabelFor(getChannelMapComboBox());
GridPane.setHalignment(channelMapLabel, HPos.RIGHT);
GridPane.setConstraints(channelMapLabel, 0, 0);
gridPane.getChildren().add(channelMapLabel);
@@ -138,6 +139,7 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getChannelMapEditButton());
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 0, 1);
gridPane.getChildren().add(poolSizeLabel);
@@ -146,6 +148,7 @@ public class MPT1327ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getTrafficChannelPoolSizeSpinner());
Label callTimeoutLabel = new Label("Call Timeout Seconds");
callTimeoutLabel.setLabelFor(getCallTimeoutSpinner());
GridPane.setHalignment(callTimeoutLabel, HPos.RIGHT);
GridPane.setConstraints(callTimeoutLabel, 2, 1);
gridPane.getChildren().add(callTimeoutLabel);

View File

@@ -19,6 +19,8 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.HexFormatter;
import io.github.dsheirer.gui.control.IntegerFormatter;
import io.github.dsheirer.gui.playlist.decoder.AuxDecoderConfigurationEditor;
@@ -135,6 +137,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
// channel bandwidth
Label bandwidthLabel = new Label("Channel Bandwidth");
AccessibilityUtil.labelGroup(bandwidthLabel, getBandwidthButton());
GridPane.setHalignment(bandwidthLabel, HPos.RIGHT);
GridPane.setConstraints(bandwidthLabel, 0, 0);
gridPane.getChildren().add(bandwidthLabel);
@@ -144,6 +147,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
//De-emphasis
Label deemphasisLabel = new Label("De-emphasis");
deemphasisLabel.setLabelFor(getDeemphasisCombo());
GridPane.setHalignment(deemphasisLabel, HPos.RIGHT);
GridPane.setConstraints(deemphasisLabel, 0, 1);
gridPane.getChildren().add(deemphasisLabel);
@@ -154,6 +158,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
// Note: normally the label and its toggle switch are one cell. They were split to make the next row
// look better. The label is manually created and placed here. Might want to create a new grid pane instead.
Label HPFLabel = new Label("High-pass Audio Filter (300 Hz)");
HPFLabel.setLabelFor(getAudioFilterEnable());
GridPane.setHalignment(HPFLabel, HPos.RIGHT);
GridPane.setConstraints(HPFLabel, 2, 1);
gridPane.getChildren().add(HPFLabel);
@@ -172,6 +177,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
*/
// talkgroup
Label talkgroupLabel = new Label("Talkgroup To Assign");
talkgroupLabel.setLabelFor(getTalkgroupField());
GridPane.setHalignment(talkgroupLabel, HPos.RIGHT);
GridPane.setConstraints(talkgroupLabel, 0, 2);
gridPane.getChildren().add(talkgroupLabel);
@@ -198,6 +204,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
modifiedProperty().set(true);
});
GridPane.setConstraints(mSquelchTypeCombo, 3, 2);
typeLabel.setLabelFor(mSquelchTypeCombo);
gridPane.getChildren().add(mSquelchTypeCombo);
// CTCSS code selector
@@ -318,6 +325,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getBasebandRecordSwitch());
Label recordBasebandLabel = new Label("Channel (Baseband I&Q)");
recordBasebandLabel.setLabelFor(getBasebandRecordSwitch());
GridPane.setHalignment(recordBasebandLabel, HPos.LEFT);
GridPane.setConstraints(recordBasebandLabel, 1, 0);
gridPane.getChildren().add(recordBasebandLabel);
@@ -381,7 +389,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
// removed label from toggle switch so that the label and the switch can be in different columns
// to make things look better on the next line. Perhaps make a new grid pane instead.
//mAudioFilterEnable = new ToggleSwitch("High-Pass Audio Filter (300 Hz)");
mAudioFilterEnable = new ToggleSwitch("");
mAudioFilterEnable = new AccessibleToggleSwitch("");
mAudioFilterEnable.setTooltip(new Tooltip("High-pass filter to remove DC offset and sub-audible signalling"));
mAudioFilterEnable.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}
@@ -396,7 +404,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
{
if(mALCEnable == null)
{
mALCEnable = new ToggleSwitch("Automatic Level Control");
mALCEnable = new AccessibleToggleSwitch("Automatic Level Control");
mALCEnable.setTooltip(new Tooltip("Automatic Level Control (ALC). Tries to make the volume of each received transmission the same."));
mALCEnable.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}
@@ -518,7 +526,7 @@ public class NBFMConfigurationEditor extends ChannelConfigurationEditor
{
if(mBasebandRecordSwitch == null)
{
mBasebandRecordSwitch = new ToggleSwitch();
mBasebandRecordSwitch = new AccessibleToggleSwitch();
mBasebandRecordSwitch.setDisable(true);
mBasebandRecordSwitch.setTextAlignment(TextAlignment.RIGHT);
mBasebandRecordSwitch.selectedProperty()

View File

@@ -19,6 +19,8 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -148,6 +150,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label mode = new Label("Mode:");
AccessibilityUtil.labelGroup(mode, getTransmissionModeButton());
GridPane.setHalignment(mode, HPos.RIGHT);
GridPane.setConstraints(mode, 0, row);
gridPane.getChildren().add(mode);
@@ -156,6 +159,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getTransmissionModeButton());
Label encoding = new Label("Talker Alias Encoding:");
encoding.setLabelFor(getEncodingComboBox());
GridPane.setHalignment(encoding, HPos.RIGHT);
GridPane.setConstraints(encoding, 2, row);
gridPane.getChildren().add(encoding);
@@ -164,6 +168,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getEncodingComboBox());
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 4, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -205,9 +210,11 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
editorBox.setSpacing(5);
Label lcnLabel = new Label("Channel Number");
lcnLabel.setLabelFor(getChannelField());
editorBox.getChildren().addAll(lcnLabel, getChannelField());
Label downlinkLabel = new Label("Downlink Frequency (MHz)");
downlinkLabel.setLabelFor(getDownlinkFrequencyField());
downlinkLabel.setPadding(new Insets(0,0,0,5));
editorBox.getChildren().addAll(downlinkLabel,getDownlinkFrequencyField());
@@ -312,6 +319,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
if(mChannelMapTable == null)
{
mChannelMapTable = new TableView<>(FXCollections.observableArrayList(ObservableChannelFrequency.extractor()));
mChannelMapTable.setAccessibleText("Channel number (LCN) to frequency map");
mChannelMapTable.setPrefHeight(100.0);
TableColumn<ObservableChannelFrequency,Number> channelColumn = new TableColumn<>("Channel");
@@ -401,6 +409,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
if(mAddTimeslotFrequencyButton == null)
{
mAddTimeslotFrequencyButton = new Button("Add");
mAddTimeslotFrequencyButton.setAccessibleText("Add channel frequency");
mAddTimeslotFrequencyButton.setMaxWidth(Double.MAX_VALUE);
mAddTimeslotFrequencyButton.setOnAction(event -> addChannelFrequency());
}
@@ -425,6 +434,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
if(mDeleteButton == null)
{
mDeleteButton = new Button("Delete");
mDeleteButton.setAccessibleText("Delete channel frequency");
mDeleteButton.setDisable(true);
mDeleteButton.setMaxWidth(Double.MAX_VALUE);
mDeleteButton.setOnAction(event -> {
@@ -519,7 +529,8 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsToggle == null)
{
mIgnoreDataCallsToggle = new ToggleSwitch("Data Calls");
mIgnoreDataCallsToggle = new AccessibleToggleSwitch("Data Calls");
mIgnoreDataCallsToggle.setAccessibleText("Ignore data calls");
mIgnoreDataCallsToggle.setDisable(true);
mIgnoreDataCallsToggle.selectedProperty().addListener((o, ov, nv) -> modifiedProperty().set(true));
}
@@ -534,7 +545,8 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreEncryptedCallsToggle == null)
{
mIgnoreEncryptedCallsToggle = new ToggleSwitch("Encrypted Calls");
mIgnoreEncryptedCallsToggle = new AccessibleToggleSwitch("Encrypted Calls");
mIgnoreEncryptedCallsToggle.setAccessibleText("Ignore encrypted calls");
mIgnoreEncryptedCallsToggle.setDisable(true);
mIgnoreEncryptedCallsToggle.selectedProperty().addListener((o, ov, nv) -> modifiedProperty().set(true));
}
@@ -546,7 +558,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -559,7 +571,7 @@ public class NXDNConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeLegacyToneLevelsButton == null)
{
mJmbeLegacyToneLevelsButton = new ToggleSwitch();
mJmbeLegacyToneLevelsButton = new AccessibleToggleSwitch();
mJmbeLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));

View File

@@ -19,6 +19,8 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
import io.github.dsheirer.gui.playlist.source.FrequencyEditor;
@@ -129,6 +131,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label modulationLabel = new Label("Modulation");
AccessibilityUtil.labelGroup(modulationLabel, getModulationSegmentedButton());
GridPane.setHalignment(modulationLabel, HPos.RIGHT);
GridPane.setConstraints(modulationLabel, 0, row);
gridPane.getChildren().add(modulationLabel);
@@ -137,6 +140,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().addAll(getModulationSegmentedButton());
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 2, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -148,6 +152,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreDataCallsButton());
Label directionLabel = new Label("Ignore Data Calls");
directionLabel.setLabelFor(getIgnoreDataCallsButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 5, row);
gridPane.getChildren().add(directionLabel);
@@ -268,7 +273,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -281,7 +286,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{
if(mLegacyToneLevelsButton == null)
{
mLegacyToneLevelsButton = new ToggleSwitch();
mLegacyToneLevelsButton = new AccessibleToggleSwitch();
mLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));
@@ -342,7 +347,7 @@ public class P25P1ConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsButton == null)
{
mIgnoreDataCallsButton = new ToggleSwitch();
mIgnoreDataCallsButton = new AccessibleToggleSwitch();
mIgnoreDataCallsButton.setDisable(true);
mIgnoreDataCallsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));

View File

@@ -19,6 +19,7 @@
package io.github.dsheirer.gui.playlist.channel;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.gui.playlist.eventlog.EventLogConfigurationEditor;
import io.github.dsheirer.gui.playlist.record.RecordConfigurationEditor;
@@ -124,6 +125,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
int row = 0;
Label poolSizeLabel = new Label("Max Traffic Channels");
poolSizeLabel.setLabelFor(getTrafficChannelPoolSizeSpinner());
GridPane.setHalignment(poolSizeLabel, HPos.RIGHT);
GridPane.setConstraints(poolSizeLabel, 0, row);
gridPane.getChildren().add(poolSizeLabel);
@@ -135,11 +137,13 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getIgnoreDataCallsButton());
Label directionLabel = new Label("Ignore Data Calls");
directionLabel.setLabelFor(getIgnoreDataCallsButton());
GridPane.setHalignment(directionLabel, HPos.LEFT);
GridPane.setConstraints(directionLabel, 3, row);
gridPane.getChildren().add(directionLabel);
Label wacnLabel = new Label("WACN");
wacnLabel.setLabelFor(getWacnTextField());
GridPane.setHalignment(wacnLabel, HPos.RIGHT);
GridPane.setConstraints(wacnLabel, 0, ++row);
gridPane.getChildren().add(wacnLabel);
@@ -148,6 +152,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getWacnTextField());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 2, row);
gridPane.getChildren().add(systemLabel);
@@ -156,6 +161,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
gridPane.getChildren().add(getSystemTextField());
Label nacLabel = new Label("NAC");
nacLabel.setLabelFor(getNacTextField());
GridPane.setHalignment(nacLabel, HPos.RIGHT);
GridPane.setConstraints(nacLabel, 4, row);
gridPane.getChildren().add(nacLabel);
@@ -183,7 +189,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{
if(mJmbeAGCButton == null)
{
mJmbeAGCButton = new ToggleSwitch();
mJmbeAGCButton = new AccessibleToggleSwitch();
mJmbeAGCButton.setTooltip(new Tooltip("Automatic Gain Control to automatically adjust call audio volume"));
mJmbeAGCButton.setDisable(true);
mJmbeAGCButton.selectedProperty().addListener((o, old, n) -> modifiedProperty().set(true));
@@ -196,7 +202,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{
if(mLegacyToneLevelsButton == null)
{
mLegacyToneLevelsButton = new ToggleSwitch();
mLegacyToneLevelsButton = new AccessibleToggleSwitch();
mLegacyToneLevelsButton.setTooltip(new Tooltip(
"Restore JMBE 1.x AMBE tone levels. Requires a supporting JMBE library; " +
"stock libraries ignore this option. Tone Volume still adjusts the selected level."));
@@ -298,7 +304,7 @@ public class P25P2ConfigurationEditor extends ChannelConfigurationEditor
{
if(mIgnoreDataCallsButton == null)
{
mIgnoreDataCallsButton = new ToggleSwitch();
mIgnoreDataCallsButton = new AccessibleToggleSwitch();
mIgnoreDataCallsButton.setDisable(true);
mIgnoreDataCallsButton.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));

View File

@@ -276,6 +276,7 @@ public class ChannelMapEditor extends SplitPane
if(mChannelMapListView == null)
{
mChannelMapListView = new ListView<>();
mChannelMapListView.setAccessibleText("Channel maps");
mChannelMapListView.setItems(mChannelMapModel.getChannelMaps());
mChannelMapListView.getSelectionModel().selectedItemProperty()
.addListener((observable, oldValue, newValue) -> {
@@ -390,6 +391,7 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.setHgap(5);
Label firstLabel = new Label("First Channel");
firstLabel.setLabelFor(getFirstField());
GridPane.setHalignment(firstLabel, HPos.RIGHT);
GridPane.setConstraints(firstLabel, 0, 0);
mChannelRangePane.getChildren().add(firstLabel);
@@ -399,6 +401,7 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.getChildren().add(getFirstField());
Label lastLabel = new Label("Last Channel");
lastLabel.setLabelFor(getLastField());
GridPane.setHalignment(lastLabel, HPos.RIGHT);
GridPane.setConstraints(lastLabel, 0, 1);
mChannelRangePane.getChildren().add(lastLabel);
@@ -408,6 +411,7 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.getChildren().add(getLastField());
Label baseLabel = new Label("Base Frequency (Hz)");
baseLabel.setLabelFor(getBaseFrequencyField());
GridPane.setHalignment(baseLabel, HPos.RIGHT);
GridPane.setConstraints(baseLabel, 0, 2);
mChannelRangePane.getChildren().add(baseLabel);
@@ -417,6 +421,7 @@ public class ChannelMapEditor extends SplitPane
mChannelRangePane.getChildren().add(getBaseFrequencyField());
Label stepSizeLabel = new Label("Step Size (Hz)");
stepSizeLabel.setLabelFor(getStepSizeField());
GridPane.setHalignment(stepSizeLabel, HPos.RIGHT);
GridPane.setConstraints(stepSizeLabel, 0, 3);
mChannelRangePane.getChildren().add(stepSizeLabel);
@@ -445,7 +450,9 @@ public class ChannelMapEditor extends SplitPane
nameBox.setSpacing(10);
nameBox.setAlignment(Pos.CENTER);
HBox.setHgrow(getNameField(), Priority.ALWAYS);
nameBox.getChildren().addAll(new Label("Name"), getNameField());
Label nameLabel = new Label("Name");
nameLabel.setLabelFor(getNameField());
nameBox.getChildren().addAll(nameLabel, getNameField());
VBox contentsBox = new VBox();
VBox.setVgrow(nameBox, Priority.NEVER);
@@ -599,6 +606,7 @@ public class ChannelMapEditor extends SplitPane
if(mChannelRangeTableView == null)
{
mChannelRangeTableView = new TableView<>();
mChannelRangeTableView.setAccessibleText("Channel ranges");
TableColumn<ChannelRange,Integer> firstColumn = new TableColumn("First");
firstColumn.setCellValueFactory(new PropertyValueFactory<ChannelRange,Integer>("firstChannel"));
@@ -790,6 +798,8 @@ public class ChannelMapEditor extends SplitPane
item == null || empty);
this.setStyle(invalidRange ? BACKGROUND_COLOR_RED : BACKGROND_COLOR_NONE);
//Invalid ranges are only shown in red, so also report them to screen readers
setAccessibleText(invalidRange && item != null && !empty ? item + ", invalid or overlapping range" : null);
}
@Override

View File

@@ -22,6 +22,7 @@
package io.github.dsheirer.gui.playlist.decoder;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.module.decode.DecoderType;
import io.github.dsheirer.module.decode.config.AuxDecodeConfiguration;
@@ -121,6 +122,7 @@ public class AuxDecoderConfigurationEditor extends Editor<AuxDecodeConfiguration
getChildren().add(getToggleSwitch());
Label label = new Label(mDecoderType.getDisplayString());
label.setLabelFor(getToggleSwitch());
GridPane.setHalignment(label, HPos.LEFT);
GridPane.setConstraints(label, 1, 0);
getChildren().add(label);
@@ -130,7 +132,7 @@ public class AuxDecoderConfigurationEditor extends Editor<AuxDecodeConfiguration
{
if(mToggleSwitch == null)
{
mToggleSwitch = new ToggleSwitch();
mToggleSwitch = new AccessibleToggleSwitch();
mToggleSwitch.setDisable(true);
mToggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -22,6 +22,7 @@
package io.github.dsheirer.gui.playlist.eventlog;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.module.log.EventLogType;
import io.github.dsheirer.module.log.config.EventLogConfiguration;
@@ -117,6 +118,7 @@ public class EventLogConfigurationEditor extends Editor<EventLogConfiguration>
getChildren().add(getToggleSwitch());
Label label = new Label(mEventLogType.getDisplayString());
label.setLabelFor(getToggleSwitch());
GridPane.setHalignment(label, HPos.LEFT);
GridPane.setConstraints(label, 1, 0);
getChildren().add(label);
@@ -126,7 +128,7 @@ public class EventLogConfigurationEditor extends Editor<EventLogConfiguration>
{
if(mToggleSwitch == null)
{
mToggleSwitch = new ToggleSwitch();
mToggleSwitch = new AccessibleToggleSwitch();
mToggleSwitch.setDisable(true);
mToggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -127,6 +127,7 @@ public class PlaylistManagerEditor extends HBox
if(mPlaylistTableView == null)
{
mPlaylistTableView = new TableView<>();
mPlaylistTableView.setAccessibleText("Playlists");
TableColumn<Path,String> iconColumn = new TableColumn("Selected");
iconColumn.setPrefWidth(100);
iconColumn.setCellFactory(new Callback<TableColumn<Path,String>,TableCell<Path,String>>()
@@ -144,6 +145,7 @@ public class PlaylistManagerEditor extends HBox
if(empty || getTableRow() == null || getTableRow().getItem() == null)
{
setGraphic(null);
setAccessibleText(null);
}
else
{
@@ -154,16 +156,19 @@ public class PlaylistManagerEditor extends HBox
IconNode iconNode = new IconNode(FontAwesome.CHECK);
iconNode.setFill(Color.GREEN);
setGraphic(iconNode);
setAccessibleText("Selected");
}
else if(!path.toFile().exists())
{
IconNode iconNode = new IconNode(FontAwesome.TIMES);
iconNode.setFill(Color.RED);
setGraphic(iconNode);
setAccessibleText("File not found");
}
else
{
setGraphic(null);
setAccessibleText("Not selected");
}
}
}

View File

@@ -138,6 +138,7 @@ public class AgencyEditor extends VBox
if(mAgencyListView == null)
{
mAgencyListView = new ListView<>();
mAgencyListView.setAccessibleText("Agencies");
mAgencyListView.setPrefHeight(200);
mAgencyListView.setCellFactory(param -> new AgencyListCell());
mAgencyListView.getSelectionModel().selectedItemProperty()

View File

@@ -94,6 +94,7 @@ public class AgencyFrequencyEditor extends GridPane
getColumnConstraints().addAll(column1, column2, column3);
Label categoryLabel = new Label("Category");
categoryLabel.setLabelFor(getCategoryComboBox());
GridPane.setConstraints(categoryLabel, 0, row);
GridPane.setHalignment(categoryLabel, HPos.RIGHT);
getChildren().add(categoryLabel);
@@ -103,6 +104,7 @@ public class AgencyFrequencyEditor extends GridPane
getChildren().add(getCategoryComboBox());
Label subCategoryLabel = new Label("Sub-Category");
subCategoryLabel.setLabelFor(getSubCategoryComboBox());
GridPane.setConstraints(subCategoryLabel, 0, ++row);
GridPane.setHalignment(subCategoryLabel, HPos.RIGHT);
getChildren().add(subCategoryLabel);
@@ -207,6 +209,7 @@ public class AgencyFrequencyEditor extends GridPane
if(mFrequencyTableView == null)
{
mFrequencyTableView = new TableView<>();
mFrequencyTableView.setAccessibleText("Agency frequencies");
mFrequencyTableView.setMaxHeight(Double.MAX_VALUE);
mFrequencyTableView.setPlaceholder(getPlaceholderLabel());

View File

@@ -97,6 +97,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(detailsLabel);
Label alphaLabel = new Label("Alpha Tag");
alphaLabel.setLabelFor(getAlphaTagTextField());
GridPane.setHalignment(alphaLabel, HPos.RIGHT);
GridPane.setConstraints(alphaLabel, 0, ++row);
gridPane.getChildren().add(alphaLabel);
@@ -106,6 +107,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getAlphaTagTextField());
Label toneLabel = new Label("Tone");
toneLabel.setLabelFor(getToneTextField());
GridPane.setHalignment(toneLabel, HPos.RIGHT);
GridPane.setConstraints(toneLabel, 0, ++row);
gridPane.getChildren().add(toneLabel);
@@ -115,6 +117,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getToneTextField());
Label modeLabel = new Label("Mode");
modeLabel.setLabelFor(getModeTextField());
GridPane.setHalignment(modeLabel, HPos.RIGHT);
GridPane.setConstraints(modeLabel, 0, ++row);
gridPane.getChildren().add(modeLabel);
@@ -124,6 +127,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getModeTextField());
Label frequencyLabel = new Label("Frequency");
frequencyLabel.setLabelFor(getFrequencyTextField());
GridPane.setHalignment(frequencyLabel, HPos.RIGHT);
GridPane.setConstraints(frequencyLabel, 0, ++row);
gridPane.getChildren().add(frequencyLabel);
@@ -141,6 +145,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(createLabel);
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, ++row);
gridPane.getChildren().add(systemLabel);
@@ -150,6 +155,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getSystemTextField());
Label siteLabel = new Label("Site");
siteLabel.setLabelFor(getSiteTextField());
GridPane.setHalignment(siteLabel, HPos.RIGHT);
GridPane.setConstraints(siteLabel, 0, ++row);
gridPane.getChildren().add(siteLabel);
@@ -159,6 +165,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getSiteTextField());
Label nameLabel = new Label("Name");
nameLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(nameLabel, HPos.RIGHT);
GridPane.setConstraints(nameLabel, 0, ++row);
gridPane.getChildren().add(nameLabel);
@@ -168,6 +175,7 @@ public class FrequencyEditor extends VBox
gridPane.getChildren().add(getNameTextField());
Label decoderLabel = new Label("Decoder");
decoderLabel.setLabelFor(getDecoderTextField());
GridPane.setHalignment(decoderLabel, HPos.RIGHT);
GridPane.setConstraints(decoderLabel, 0, ++row);
gridPane.getChildren().add(decoderLabel);

View File

@@ -25,6 +25,7 @@ import io.github.dsheirer.rrapi.response.Fault;
import io.github.dsheirer.rrapi.type.AuthorizationInformation;
import io.github.dsheirer.service.radioreference.RadioReference;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
@@ -128,6 +129,7 @@ public class LoginDialog extends Dialog<AuthorizationInformation>
mGridPane.setVgap(5.0);
Label userNameLabel = new Label("User Name:");
userNameLabel.setLabelFor(getUserNameText());
GridPane.setHalignment(userNameLabel, HPos.RIGHT);
GridPane.setConstraints(userNameLabel, 0, 0);
mGridPane.getChildren().add(userNameLabel);
@@ -137,6 +139,8 @@ public class LoginDialog extends Dialog<AuthorizationInformation>
mGridPane.getChildren().add(getUserNameText());
Label passwordLabel = new Label("Password:");
passwordLabel.labelForProperty().bind(Bindings.when(getPasswordText().visibleProperty())
.then((Node)getPasswordText()).otherwise(getPasswordField()));
GridPane.setHalignment(passwordLabel, HPos.RIGHT);
GridPane.setConstraints(passwordLabel, 0, 1);
mGridPane.getChildren().add(passwordLabel);
@@ -229,6 +233,7 @@ public class LoginDialog extends Dialog<AuthorizationInformation>
if(mShowPasswordCheckBox == null)
{
mShowPasswordCheckBox = new CheckBox("Show");
mShowPasswordCheckBox.setAccessibleText("Show password");
mShowPasswordCheckBox.setSelected(mUserPreferences.getRadioReferencePreference().getShowPassword());
mShowPasswordCheckBox.setOnAction(new EventHandler<ActionEvent>()
{
@@ -281,6 +286,7 @@ public class LoginDialog extends Dialog<AuthorizationInformation>
public void handle(ActionEvent event)
{
getTestConnectionButton().setDisable(true);
getTestConnectionButton().setAccessibleText(null);
getTestPassIcon().setVisible(false);
getTestFailIcon().setVisible(false);
getTestExpiredIcon().setVisible(false);
@@ -327,6 +333,8 @@ public class LoginDialog extends Dialog<AuthorizationInformation>
getTestPassIcon().setVisible(true);
getTestFailIcon().setVisible(false);
getTestExpiredIcon().setVisible(false);
//Success is only shown as an icon, so report it in the button's accessible name
getTestConnectionButton().setAccessibleText("Test Connection: login successful");
}
else if (loginStatus == RadioReference.LoginStatus.EXPIRED_PREMIUM)
{

View File

@@ -377,6 +377,7 @@ public class RadioReferenceEditor extends BorderPane implements Consumer<Authori
mComboBoxPane.getColumnConstraints().addAll(column1, column2, column3);
Label countryLabel = new Label("Country");
countryLabel.setLabelFor(getCountryComboBox());
GridPane.setConstraints(countryLabel, 0, 0);
mComboBoxPane.getChildren().add(countryLabel);
@@ -385,6 +386,7 @@ public class RadioReferenceEditor extends BorderPane implements Consumer<Authori
mComboBoxPane.getChildren().add(getCountryComboBox());
Label stateLabel = new Label("State");
stateLabel.setLabelFor(getStateComboBox());
GridPane.setConstraints(stateLabel, 1, 0);
mComboBoxPane.getChildren().add(stateLabel);
@@ -393,6 +395,7 @@ public class RadioReferenceEditor extends BorderPane implements Consumer<Authori
mComboBoxPane.getChildren().add(getStateComboBox());
Label countyLabel = new Label("County");
countyLabel.setLabelFor(getCountyComboBox());
GridPane.setConstraints(countyLabel, 2, 0);
mComboBoxPane.getChildren().add(countyLabel);

View File

@@ -22,6 +22,7 @@ package io.github.dsheirer.gui.playlist.radioreference;
import io.github.dsheirer.alias.AliasModel;
import io.github.dsheirer.controller.channel.Channel;
import io.github.dsheirer.eventbus.MyEventBus;
import io.github.dsheirer.gui.control.AccessibilityUtil;
import io.github.dsheirer.gui.control.MaxLengthUnaryOperator;
import io.github.dsheirer.gui.playlist.channel.ViewChannelRequest;
import io.github.dsheirer.module.decode.DecoderFactory;
@@ -156,6 +157,7 @@ public class SiteEditor extends GridPane
getChildren().add(getSiteFrequencyTableView());
Label frequenciesLabel = new Label("Frequencies:");
AccessibilityUtil.labelGroup(frequenciesLabel, getFrequenciesSegmentedButton());
GridPane.setConstraints(frequenciesLabel, 1, row);
GridPane.setHalignment(frequenciesLabel, HPos.RIGHT);
getChildren().add(frequenciesLabel);
@@ -164,6 +166,7 @@ public class SiteEditor extends GridPane
getChildren().add(getFrequenciesSegmentedButton());
Label configurationsLabel = new Label("Configurations:");
AccessibilityUtil.labelGroup(configurationsLabel, getConfigurationsSegmentedButton());
GridPane.setConstraints(configurationsLabel, 1, ++row);
GridPane.setHalignment(configurationsLabel, HPos.RIGHT);
getChildren().add(configurationsLabel);
@@ -176,9 +179,11 @@ public class SiteEditor extends GridPane
getChildren().add(getP25ControlLabel());
GridPane.setConstraints(getP25ControlSegmentedButton(), 2, row);
AccessibilityUtil.labelGroup(getP25ControlLabel(), getP25ControlSegmentedButton());
getChildren().add(getP25ControlSegmentedButton());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemTextField());
GridPane.setConstraints(systemLabel, 1, ++row);
GridPane.setHalignment(systemLabel, HPos.RIGHT);
getChildren().add(systemLabel);
@@ -188,6 +193,7 @@ public class SiteEditor extends GridPane
getChildren().add(getSystemTextField());
Label siteLabel = new Label("Site");
siteLabel.setLabelFor(getSiteTextField());
GridPane.setConstraints(siteLabel, 1, ++row);
GridPane.setHalignment(siteLabel, HPos.RIGHT);
getChildren().add(siteLabel);
@@ -197,6 +203,7 @@ public class SiteEditor extends GridPane
getChildren().add(getSiteTextField());
Label nameLabel = new Label("Name");
nameLabel.setLabelFor(getNameTextField());
GridPane.setConstraints(nameLabel, 1, ++row);
GridPane.setHalignment(nameLabel, HPos.RIGHT);
getChildren().add(nameLabel);
@@ -206,6 +213,7 @@ public class SiteEditor extends GridPane
getChildren().add(getNameTextField());
Label aliasListLabel = new Label("Alias List");
aliasListLabel.setLabelFor(getAliasListNameComboBox());
GridPane.setConstraints(aliasListLabel, 1, ++row);
GridPane.setHalignment(aliasListLabel, HPos.RIGHT);
getChildren().add(aliasListLabel);
@@ -1138,6 +1146,7 @@ public class SiteEditor extends GridPane
if(mSiteFrequencyTableView == null)
{
mSiteFrequencyTableView = new TableView<>();
mSiteFrequencyTableView.setAccessibleText("Site frequencies");
mSiteFrequencyTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
mSiteFrequencyTableView.setPlaceholder(new Label("Please select a site to view frequencies"));

View File

@@ -103,7 +103,9 @@ public class SystemEditor extends VBox
systemBox.setAlignment(Pos.CENTER_LEFT);
systemBox.setSpacing(5);
systemBox.setMaxWidth(Double.MAX_VALUE);
systemBox.getChildren().addAll(new Label("System"), getSystemComboBox());
Label systemLabel = new Label("System");
systemLabel.setLabelFor(getSystemComboBox());
systemBox.getChildren().addAll(systemLabel, getSystemComboBox());
VBox.setVgrow(getTabPane(), Priority.ALWAYS);
getChildren().addAll(systemBox, getTabPane());
}
@@ -388,11 +390,14 @@ public class SystemEditor extends VBox
setGraphic(null);
mName.setText(null);
mProtocol.setText(null);
setAccessibleText(null);
}
else
{
mName.setText(item.getName());
mProtocol.setText(getType(item));
//Text is shown in nested labels, so expose it as the cell's accessible text
setAccessibleText(item.getName() + ", " + getType(item));
if(isSupported(item))
{

View File

@@ -214,6 +214,7 @@ public class SystemSiteSelectionEditor extends GridPane
if(mSiteTableView == null)
{
mSiteTableView = new TableView<>();
mSiteTableView.setAccessibleText("Sites");
mSiteTableView.setPlaceholder(getPlaceholderLabel());
TableColumn systemColumn = new TableColumn();

View File

@@ -128,6 +128,7 @@ public class SystemTalkgroupSelectionEditor extends GridPane
listBox.setSpacing(5);
listBox.setAlignment(Pos.CENTER);
Label importLabel = new Label("Import To Alias List:");
importLabel.setLabelFor(getAliasListNameComboBox());
listBox.getChildren().addAll(importLabel, getAliasListNameComboBox(), getNewAliasListButton());
GridPane.setConstraints(listBox, 0, row);
getChildren().add(listBox);
@@ -139,7 +140,9 @@ public class SystemTalkgroupSelectionEditor extends GridPane
HBox searchBox = new HBox();
searchBox.setSpacing(5);
searchBox.setAlignment(Pos.CENTER);
searchBox.getChildren().addAll(new Label("Search"), getSearchField());
Label searchLabel = new Label("Search");
searchLabel.setLabelFor(getSearchField());
searchBox.getChildren().addAll(searchLabel, getSearchField());
GridPane.setConstraints(searchBox, 0, ++row);
getChildren().add(searchBox);
@@ -151,7 +154,9 @@ public class SystemTalkgroupSelectionEditor extends GridPane
categoryBox.setAlignment(Pos.CENTER_LEFT);
categoryBox.setSpacing(5);
HBox.setHgrow(getTalkgroupCategoryComboBox(), Priority.ALWAYS);
categoryBox.getChildren().addAll(new Label("Category"), getTalkgroupCategoryComboBox());
Label categoryLabel = new Label("Category");
categoryLabel.setLabelFor(getTalkgroupCategoryComboBox());
categoryBox.getChildren().addAll(categoryLabel, getTalkgroupCategoryComboBox());
GridPane.setHgrow(categoryBox, Priority.ALWAYS);
GridPane.setConstraints(categoryBox, 0, ++row);
getChildren().add(categoryBox);
@@ -612,6 +617,7 @@ public class SystemTalkgroupSelectionEditor extends GridPane
if(mTalkgroupTableView == null)
{
mTalkgroupTableView = new TableView<>();
mTalkgroupTableView.setAccessibleText("Talkgroups");
mTalkgroupTableView.setMaxHeight(Double.MAX_VALUE);
TableColumn<AliasedTalkgroup,String> talkgroupColumn = new TableColumn("Talkgroup");
talkgroupColumn.setCellValueFactory(new PropertyValueFactory<>("talkgroup"));

View File

@@ -80,6 +80,7 @@ public class TalkgroupEditor extends GridPane
getChildren().add(radioReferenceLabel);
Label talkgroupLabel = new Label("Talkgroup");
talkgroupLabel.setLabelFor(getTalkgroupTextField());
GridPane.setConstraints(talkgroupLabel, 0, ++row);
GridPane.setHalignment(talkgroupLabel, HPos.RIGHT);
getChildren().add(talkgroupLabel);
@@ -89,6 +90,7 @@ public class TalkgroupEditor extends GridPane
getChildren().add(getTalkgroupTextField());
Label alphaLabel = new Label("Alpha Tag");
alphaLabel.setLabelFor(getAlphaTagTextField());
GridPane.setConstraints(alphaLabel, 0, ++row);
GridPane.setHalignment(alphaLabel, HPos.RIGHT);
getChildren().add(alphaLabel);
@@ -98,6 +100,7 @@ public class TalkgroupEditor extends GridPane
getChildren().add(getAlphaTagTextField());
Label descriptionLabel = new Label("Description");
descriptionLabel.setLabelFor(getDescriptionTextField());
GridPane.setConstraints(descriptionLabel, 0, ++row);
GridPane.setHalignment(descriptionLabel, HPos.RIGHT);
getChildren().add(descriptionLabel);
@@ -107,6 +110,7 @@ public class TalkgroupEditor extends GridPane
getChildren().add(getDescriptionTextField());
Label modeLabel = new Label("Mode");
modeLabel.setLabelFor(getModeTextField());
GridPane.setConstraints(modeLabel, 0, ++row);
GridPane.setHalignment(modeLabel, HPos.RIGHT);
getChildren().add(modeLabel);
@@ -222,6 +226,7 @@ public class TalkgroupEditor extends GridPane
if(mNameLabel == null)
{
mNameLabel = new Label("Name");
mNameLabel.setLabelFor(getAliasNameTextField());
mNameLabel.setVisible(false);
}
@@ -233,6 +238,7 @@ public class TalkgroupEditor extends GridPane
if(mGroupLabel == null)
{
mGroupLabel = new Label("Group");
mGroupLabel.setLabelFor(getAliasGroupTextField());
mGroupLabel.setVisible(false);
}

View File

@@ -22,6 +22,7 @@
package io.github.dsheirer.gui.playlist.record;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.record.RecorderType;
import io.github.dsheirer.record.config.RecordConfiguration;
@@ -117,6 +118,7 @@ public class RecordConfigurationEditor extends Editor<RecordConfiguration>
getChildren().add(getToggleSwitch());
Label label = new Label(mRecorderType.getDisplayString());
label.setLabelFor(getToggleSwitch());
GridPane.setHalignment(label, HPos.LEFT);
GridPane.setConstraints(label, 1, 0);
getChildren().add(label);
@@ -126,7 +128,7 @@ public class RecordConfigurationEditor extends Editor<RecordConfiguration>
{
if(mToggleSwitch == null)
{
mToggleSwitch = new ToggleSwitch();
mToggleSwitch = new AccessibleToggleSwitch();
mToggleSwitch.setDisable(true);
mToggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -104,10 +104,12 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
hBox.setAlignment(Pos.CENTER_LEFT);
Label label = new Label(mAllowMultipleFrequencies ? "Frequencies (MHz)" : "Frequency (MHz)");
label.setLabelFor(getPrimaryFrequencyBox().getFrequencyField());
label.setAlignment(Pos.BASELINE_RIGHT);
hBox.getChildren().addAll(label, getFrequencyBoxContainer());
Label preferredTunerLabel = new Label("Preferred Tuner");
preferredTunerLabel.setLabelFor(getPreferredTunerComboBox());
HBox tunerBox = new HBox();
tunerBox.setAlignment(Pos.CENTER_LEFT);
tunerBox.setSpacing(10);
@@ -120,6 +122,7 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
if(mAllowMultipleFrequencies)
{
Label frequencyRotationLabel = new Label("Frequency Rotation Delay (ms)");
frequencyRotationLabel.setLabelFor(getFrequencyRotationDelaySpinner());
HBox frequencyBox = new HBox();
frequencyBox.setAlignment(Pos.CENTER_LEFT);
frequencyBox.setSpacing(10);
@@ -538,6 +541,7 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
if(mAddButton == null)
{
mAddButton = new Button("Add");
mAddButton.setAccessibleText("Add frequency");
mAddButton.setDisable(true);
mAddButton.setOnAction(event -> addFrequencyBox());
}
@@ -553,6 +557,7 @@ public class FrequencyEditor extends SourceConfigurationEditor<SourceConfigurati
if(mRemoveButton == null)
{
mRemoveButton = new Button("Remove");
mRemoveButton.setAccessibleText("Remove frequency");
mRemoveButton.setDisable(true);
mRemoveButton.setOnAction(event -> {
Alert confirm = new Alert(Alert.AlertType.CONFIRMATION,

View File

@@ -22,6 +22,7 @@ package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
import io.github.dsheirer.audio.broadcast.BroadcastEvent;
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.playlist.Editor;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.application.Platform;
@@ -205,7 +206,7 @@ public abstract class AbstractBroadcastEditor<T extends BroadcastConfiguration>
{
if(mEnabledSwitch == null)
{
mEnabledSwitch = new ToggleSwitch();
mEnabledSwitch = new AccessibleToggleSwitch();
mEnabledSwitch.setDisable(true);
mEnabledSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));

View File

@@ -25,7 +25,10 @@ package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.audio.broadcast.BroadcastConfiguration;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.beans.binding.Bindings;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
@@ -150,11 +153,24 @@ public abstract class AbstractStreamEditor<T extends BroadcastConfiguration> ext
if(mShowPasswordCheckBox == null)
{
mShowPasswordCheckBox = new CheckBox("Show");
mShowPasswordCheckBox.setAccessibleText("Show password");
}
return mShowPasswordCheckBox;
}
/**
* Links the password label to whichever password field (masked or unmasked) is currently visible, so that
* screen readers announce the label for the password field that has focus.
* @param label for the password fields
*/
protected void setPasswordLabel(Label label)
{
label.labelForProperty().bind(Bindings.when(getShowPasswordCheckBox().selectedProperty())
.then((Node)getUnMaskedPasswordTextField())
.otherwise(getMaskedPasswordTextField()));
}
protected IntegerTextField getPortTextField()
{
if(mPortTextField == null)

View File

@@ -22,6 +22,7 @@ package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyCallBroadcaster;
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyCallConfiguration;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.geometry.HPos;
@@ -133,6 +134,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
int row = 0;
Label formatLabel = new Label("Format");
formatLabel.setLabelFor(getFormatField());
GridPane.setHalignment(formatLabel, HPos.RIGHT);
GridPane.setConstraints(formatLabel, 0, row);
mEditorPane.getChildren().add(formatLabel);
@@ -141,6 +143,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getFormatField());
Label enabledLabel = new Label("Enabled");
enabledLabel.setLabelFor(getEnabledSwitch());
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
GridPane.setConstraints(enabledLabel, 2, row);
mEditorPane.getChildren().add(enabledLabel);
@@ -149,6 +152,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getEnabledSwitch());
Label systemLabel = new Label("Name");
systemLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, ++row);
mEditorPane.getChildren().add(systemLabel);
@@ -157,6 +161,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getNameTextField());
Label apiKeyLabel = new Label("API Key");
apiKeyLabel.setLabelFor(getApiKeyTextField());
GridPane.setHalignment(apiKeyLabel, HPos.RIGHT);
GridPane.setConstraints(apiKeyLabel, 0, ++row);
mEditorPane.getChildren().add(apiKeyLabel);
@@ -165,6 +170,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getApiKeyTextField());
Label systemIdLabel = new Label("System ID");
systemIdLabel.setLabelFor(getSystemIdTextField());
GridPane.setHalignment(systemIdLabel, HPos.RIGHT);
GridPane.setConstraints(systemIdLabel, 0, ++row);
mEditorPane.getChildren().add(systemIdLabel);
@@ -173,6 +179,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getSystemIdTextField());
Label hostLabel = new Label("Broadcastify URL");
hostLabel.setLabelFor(getHostTextField());
GridPane.setHalignment(hostLabel, HPos.RIGHT);
GridPane.setConstraints(hostLabel, 0, ++row);
mEditorPane.getChildren().add(hostLabel);
@@ -181,6 +188,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getHostTextField());
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
maxAgeLabel.setLabelFor(getMaxAgeTextField());
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
GridPane.setConstraints(maxAgeLabel, 0, ++row);
mEditorPane.getChildren().add(maxAgeLabel);
@@ -189,6 +197,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getMaxAgeTextField());
Label testEnabledLabel = new Label("Send Periodic Keep-Alive");
testEnabledLabel.setLabelFor(getTestEnabledToggleSwitch());
GridPane.setHalignment(testEnabledLabel, HPos.RIGHT);
GridPane.setConstraints(testEnabledLabel, 0, ++row);
mEditorPane.getChildren().add(testEnabledLabel);
@@ -197,6 +206,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
mEditorPane.getChildren().add(getTestEnabledToggleSwitch());
Label testIntervalLabel = new Label("Ping Interval (minutes)");
testIntervalLabel.setLabelFor(getTestIntervalTextField());
GridPane.setHalignment(testIntervalLabel, HPos.RIGHT);
GridPane.setConstraints(testIntervalLabel, 3, row);
mEditorPane.getChildren().add(testIntervalLabel);
@@ -263,7 +273,7 @@ public class BroadcastifyCallEditor extends AbstractBroadcastEditor<Broadcastify
{
if(mTestEnabledToggleSwitch == null)
{
mTestEnabledToggleSwitch = new ToggleSwitch();
mTestEnabledToggleSwitch = new AccessibleToggleSwitch();
mTestEnabledToggleSwitch.setDisable(true);
mTestEnabledToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));

View File

@@ -22,6 +22,7 @@ package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import io.github.dsheirer.audio.broadcast.broadcastify.BroadcastifyFeedConfiguration;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.geometry.HPos;
@@ -100,6 +101,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.setHgap(5);
Label formatLabel = new Label("Format");
formatLabel.setLabelFor(getFormatField());
GridPane.setHalignment(formatLabel, HPos.RIGHT);
GridPane.setConstraints(formatLabel, 0, 0);
mEditorPane.getChildren().add(formatLabel);
@@ -108,6 +110,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getFormatField());
Label enabledLabel = new Label("Enabled");
enabledLabel.setLabelFor(getEnabledSwitch());
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
GridPane.setConstraints(enabledLabel, 2, 0);
mEditorPane.getChildren().add(enabledLabel);
@@ -116,6 +119,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getEnabledSwitch());
Label systemLabel = new Label("Name");
systemLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, 1);
mEditorPane.getChildren().add(systemLabel);
@@ -124,6 +128,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getNameTextField());
Label hostLabel = new Label("Server");
hostLabel.setLabelFor(getHostTextField());
GridPane.setHalignment(hostLabel, HPos.RIGHT);
GridPane.setConstraints(hostLabel, 0, 2);
mEditorPane.getChildren().add(hostLabel);
@@ -132,6 +137,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getHostTextField());
Label portLabel = new Label("Port");
portLabel.setLabelFor(getPortTextField());
GridPane.setHalignment(portLabel, HPos.RIGHT);
GridPane.setConstraints(portLabel, 2, 2);
mEditorPane.getChildren().add(portLabel);
@@ -140,6 +146,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getPortTextField());
Label mountPointLabel = new Label("Mount Point");
mountPointLabel.setLabelFor(getMountPointTextField());
GridPane.setHalignment(mountPointLabel, HPos.RIGHT);
GridPane.setConstraints(mountPointLabel, 0, 3);
mEditorPane.getChildren().add(mountPointLabel);
@@ -148,6 +155,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getMountPointTextField());
Label passwordLabel = new Label("Password");
setPasswordLabel(passwordLabel);
GridPane.setHalignment(passwordLabel, HPos.RIGHT);
GridPane.setConstraints(passwordLabel, 2, 3);
mEditorPane.getChildren().add(passwordLabel);
@@ -160,6 +168,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getShowPasswordCheckBox());
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
maxAgeLabel.setLabelFor(getMaxAgeTextField());
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
GridPane.setConstraints(maxAgeLabel, 0, 4);
mEditorPane.getChildren().add(maxAgeLabel);
@@ -168,6 +177,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getMaxAgeTextField());
Label delayLabel = new Label("Delay (seconds)");
delayLabel.setLabelFor(getDelayTextField());
GridPane.setHalignment(delayLabel, HPos.RIGHT);
GridPane.setConstraints(delayLabel, 2, 4);
mEditorPane.getChildren().add(delayLabel);
@@ -176,6 +186,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
mEditorPane.getChildren().add(getDelayTextField());
Label feedIdLabel = new Label("Feed ID");
feedIdLabel.setLabelFor(getFeedIdTextField());
GridPane.setHalignment(feedIdLabel, HPos.RIGHT);
GridPane.setConstraints(feedIdLabel, 0, 5);
getEditorPane().getChildren().add(feedIdLabel);
@@ -184,6 +195,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
getEditorPane().getChildren().add(getFeedIdTextField());
Label loggingLabel = new Label("Verbose Logging");
loggingLabel.setLabelFor(getVerboseLoggingToggle());
GridPane.setHalignment(loggingLabel, HPos.RIGHT);
GridPane.setConstraints(loggingLabel, 2, 5);
getEditorPane().getChildren().add(loggingLabel);
@@ -199,7 +211,7 @@ public class BroadcastifyStreamEditor extends AbstractStreamEditor<BroadcastifyF
{
if(mVerboseLoggingToggle == null)
{
mVerboseLoggingToggle = new ToggleSwitch();
mVerboseLoggingToggle = new AccessibleToggleSwitch();
mVerboseLoggingToggle.setTooltip(new Tooltip("Turn on additional logging for connection troubleshooting"));
mVerboseLoggingToggle.setDisable(true);
mVerboseLoggingToggle.selectedProperty().addListener((ob, ol, ne) -> modifiedProperty().set(true));

View File

@@ -24,6 +24,7 @@ package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.audio.broadcast.icecast.IcecastConfiguration;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
@@ -108,6 +109,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.setHgap(5);
Label formatLabel = new Label("Format");
formatLabel.setLabelFor(getFormatField());
GridPane.setHalignment(formatLabel, HPos.RIGHT);
GridPane.setConstraints(formatLabel, 0, 0);
mEditorPane.getChildren().add(formatLabel);
@@ -117,6 +119,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getFormatField());
Label enabledLabel = new Label("Enabled");
enabledLabel.setLabelFor(getEnabledSwitch());
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
GridPane.setConstraints(enabledLabel, 2, 0);
mEditorPane.getChildren().add(enabledLabel);
@@ -125,6 +128,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getEnabledSwitch());
Label systemLabel = new Label("Name");
systemLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, 1);
mEditorPane.getChildren().add(systemLabel);
@@ -133,6 +137,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getNameTextField());
Label hostLabel = new Label("Server");
hostLabel.setLabelFor(getHostTextField());
GridPane.setHalignment(hostLabel, HPos.RIGHT);
GridPane.setConstraints(hostLabel, 0, 2);
mEditorPane.getChildren().add(hostLabel);
@@ -141,6 +146,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getHostTextField());
Label portLabel = new Label("Port");
portLabel.setLabelFor(getPortTextField());
GridPane.setHalignment(portLabel, HPos.RIGHT);
GridPane.setConstraints(portLabel, 2, 2);
mEditorPane.getChildren().add(portLabel);
@@ -149,6 +155,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getPortTextField());
Label mountPointLabel = new Label("Mount Point");
mountPointLabel.setLabelFor(getMountPointTextField());
GridPane.setHalignment(mountPointLabel, HPos.RIGHT);
GridPane.setConstraints(mountPointLabel, 0, 3);
mEditorPane.getChildren().add(mountPointLabel);
@@ -157,6 +164,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getMountPointTextField());
Label inlineLabel = new Label("Inline Metadata");
inlineLabel.setLabelFor(getInlineToggleSwitch());
GridPane.setHalignment(inlineLabel, HPos.RIGHT);
GridPane.setConstraints(inlineLabel, 2, 3);
mEditorPane.getChildren().add(inlineLabel);
@@ -165,6 +173,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getInlineToggleSwitch());
Label userNameLabel = new Label("User Name");
userNameLabel.setLabelFor(getUserNameTextField());
GridPane.setHalignment(userNameLabel, HPos.RIGHT);
GridPane.setConstraints(userNameLabel, 0, 4);
mEditorPane.getChildren().add(userNameLabel);
@@ -173,6 +182,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getUserNameTextField());
Label passwordLabel = new Label("Password");
setPasswordLabel(passwordLabel);
GridPane.setHalignment(passwordLabel, HPos.RIGHT);
GridPane.setConstraints(passwordLabel, 2, 4);
mEditorPane.getChildren().add(passwordLabel);
@@ -185,6 +195,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getShowPasswordCheckBox());
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
maxAgeLabel.setLabelFor(getMaxAgeTextField());
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
GridPane.setConstraints(maxAgeLabel, 0, 5);
mEditorPane.getChildren().add(maxAgeLabel);
@@ -193,6 +204,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getMaxAgeTextField());
Label delayLabel = new Label("Delay (seconds)");
delayLabel.setLabelFor(getDelayTextField());
GridPane.setHalignment(delayLabel, HPos.RIGHT);
GridPane.setConstraints(delayLabel, 2, 5);
mEditorPane.getChildren().add(delayLabel);
@@ -201,6 +213,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getDelayTextField());
Label descriptionLabel = new Label("Description");
descriptionLabel.setLabelFor(getDescriptionTextField());
GridPane.setHalignment(descriptionLabel, HPos.RIGHT);
GridPane.setConstraints(descriptionLabel, 0, 6);
mEditorPane.getChildren().add(descriptionLabel);
@@ -209,6 +222,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getDescriptionTextField());
Label genreLabel = new Label("Genre");
genreLabel.setLabelFor(getGenreTextField());
GridPane.setHalignment(genreLabel, HPos.RIGHT);
GridPane.setConstraints(genreLabel, 0, 7);
mEditorPane.getChildren().add(genreLabel);
@@ -217,6 +231,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
mEditorPane.getChildren().add(getGenreTextField());
Label urlLabel = new Label("URL");
urlLabel.setLabelFor(getURLTextField());
GridPane.setHalignment(urlLabel, HPos.RIGHT);
GridPane.setConstraints(urlLabel, 0, 8);
mEditorPane.getChildren().add(urlLabel);
@@ -244,7 +259,7 @@ public abstract class IcecastStreamEditor extends AbstractStreamEditor<IcecastCo
{
if(mInlineToggleSwitch == null)
{
mInlineToggleSwitch = new ToggleSwitch();
mInlineToggleSwitch = new AccessibleToggleSwitch();
mInlineToggleSwitch.setDisable(true);
mInlineToggleSwitch.selectedProperty()
.addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));

View File

@@ -131,6 +131,7 @@ public class RdioScannerEditor extends AbstractBroadcastEditor<RdioScannerConfig
int row = 0;
Label formatLabel = new Label("Format");
formatLabel.setLabelFor(getFormatField());
GridPane.setHalignment(formatLabel, HPos.RIGHT);
GridPane.setConstraints(formatLabel, 0, row);
mEditorPane.getChildren().add(formatLabel);
@@ -139,6 +140,7 @@ public class RdioScannerEditor extends AbstractBroadcastEditor<RdioScannerConfig
mEditorPane.getChildren().add(getFormatField());
Label enabledLabel = new Label("Enabled");
enabledLabel.setLabelFor(getEnabledSwitch());
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
GridPane.setConstraints(enabledLabel, 2, row);
mEditorPane.getChildren().add(enabledLabel);
@@ -147,6 +149,7 @@ public class RdioScannerEditor extends AbstractBroadcastEditor<RdioScannerConfig
mEditorPane.getChildren().add(getEnabledSwitch());
Label systemLabel = new Label("Name");
systemLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, ++row);
mEditorPane.getChildren().add(systemLabel);
@@ -155,6 +158,7 @@ public class RdioScannerEditor extends AbstractBroadcastEditor<RdioScannerConfig
mEditorPane.getChildren().add(getNameTextField());
Label apiKeyLabel = new Label("API Key");
apiKeyLabel.setLabelFor(getApiKeyTextField());
GridPane.setHalignment(apiKeyLabel, HPos.RIGHT);
GridPane.setConstraints(apiKeyLabel, 0, ++row);
mEditorPane.getChildren().add(apiKeyLabel);
@@ -163,6 +167,7 @@ public class RdioScannerEditor extends AbstractBroadcastEditor<RdioScannerConfig
mEditorPane.getChildren().add(getApiKeyTextField());
Label systemIdLabel = new Label("System ID");
systemIdLabel.setLabelFor(getSystemIdTextField());
GridPane.setHalignment(systemIdLabel, HPos.RIGHT);
GridPane.setConstraints(systemIdLabel, 0, ++row);
mEditorPane.getChildren().add(systemIdLabel);
@@ -171,6 +176,7 @@ public class RdioScannerEditor extends AbstractBroadcastEditor<RdioScannerConfig
mEditorPane.getChildren().add(getSystemIdTextField());
Label hostLabel = new Label("RdioScanner URL");
hostLabel.setLabelFor(getHostTextField());
GridPane.setHalignment(hostLabel, HPos.RIGHT);
GridPane.setConstraints(hostLabel, 0, ++row);
mEditorPane.getChildren().add(hostLabel);
@@ -184,6 +190,7 @@ public class RdioScannerEditor extends AbstractBroadcastEditor<RdioScannerConfig
mEditorPane.getChildren().add(apiPath);
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
maxAgeLabel.setLabelFor(getMaxAgeTextField());
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
GridPane.setConstraints(maxAgeLabel, 0, ++row);
mEditorPane.getChildren().add(maxAgeLabel);

View File

@@ -25,6 +25,7 @@ package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import io.github.dsheirer.audio.broadcast.shoutcast.v1.ShoutcastV1Configuration;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
@@ -102,6 +103,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.setHgap(5);
Label formatLabel = new Label("Format");
formatLabel.setLabelFor(getFormatField());
GridPane.setHalignment(formatLabel, HPos.RIGHT);
GridPane.setConstraints(formatLabel, 0, 0);
mEditorPane.getChildren().add(formatLabel);
@@ -111,6 +113,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getFormatField());
Label enabledLabel = new Label("Enabled");
enabledLabel.setLabelFor(getEnabledSwitch());
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
GridPane.setConstraints(enabledLabel, 2, 0);
mEditorPane.getChildren().add(enabledLabel);
@@ -119,6 +122,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getEnabledSwitch());
Label systemLabel = new Label("Name");
systemLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, 1);
mEditorPane.getChildren().add(systemLabel);
@@ -127,6 +131,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getNameTextField());
Label publicLabel = new Label("Public");
publicLabel.setLabelFor(getPublicToggleSwitch());
GridPane.setHalignment(publicLabel, HPos.RIGHT);
GridPane.setConstraints(publicLabel, 2, 1);
mEditorPane.getChildren().add(publicLabel);
@@ -135,6 +140,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getPublicToggleSwitch());
Label hostLabel = new Label("Server");
hostLabel.setLabelFor(getHostTextField());
GridPane.setHalignment(hostLabel, HPos.RIGHT);
GridPane.setConstraints(hostLabel, 0, 2);
mEditorPane.getChildren().add(hostLabel);
@@ -143,6 +149,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getHostTextField());
Label portLabel = new Label("Port");
portLabel.setLabelFor(getPortTextField());
GridPane.setHalignment(portLabel, HPos.RIGHT);
GridPane.setConstraints(portLabel, 2, 2);
mEditorPane.getChildren().add(portLabel);
@@ -151,6 +158,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getPortTextField());
Label passwordLabel = new Label("Password");
setPasswordLabel(passwordLabel);
GridPane.setHalignment(passwordLabel, HPos.RIGHT);
GridPane.setConstraints(passwordLabel, 0, 3);
mEditorPane.getChildren().add(passwordLabel);
@@ -163,6 +171,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getShowPasswordCheckBox());
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
maxAgeLabel.setLabelFor(getMaxAgeTextField());
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
GridPane.setConstraints(maxAgeLabel, 0, 4);
mEditorPane.getChildren().add(maxAgeLabel);
@@ -171,6 +180,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getMaxAgeTextField());
Label delayLabel = new Label("Delay (seconds)");
delayLabel.setLabelFor(getDelayTextField());
GridPane.setHalignment(delayLabel, HPos.RIGHT);
GridPane.setConstraints(delayLabel, 2, 4);
mEditorPane.getChildren().add(delayLabel);
@@ -179,6 +189,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getDelayTextField());
Label descriptionLabel = new Label("Description");
descriptionLabel.setLabelFor(getDescriptionTextField());
GridPane.setHalignment(descriptionLabel, HPos.RIGHT);
GridPane.setConstraints(descriptionLabel, 0, 5);
mEditorPane.getChildren().add(descriptionLabel);
@@ -187,6 +198,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
mEditorPane.getChildren().add(getDescriptionTextField());
Label genreLabel = new Label("Genre");
genreLabel.setLabelFor(getGenreTextField());
GridPane.setHalignment(genreLabel, HPos.RIGHT);
GridPane.setConstraints(genreLabel, 0, 6);
mEditorPane.getChildren().add(genreLabel);
@@ -226,7 +238,7 @@ public class ShoutcastV1StreamEditor extends AbstractStreamEditor<ShoutcastV1Con
{
if(mPublicToggleSwitch == null)
{
mPublicToggleSwitch = new ToggleSwitch();
mPublicToggleSwitch = new AccessibleToggleSwitch();
mPublicToggleSwitch.setDisable(true);
mPublicToggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -25,6 +25,7 @@ package io.github.dsheirer.gui.playlist.streaming;
import io.github.dsheirer.audio.broadcast.BroadcastServerType;
import io.github.dsheirer.audio.broadcast.shoutcast.v2.ShoutcastV2Configuration;
import io.github.dsheirer.gui.control.AccessibleToggleSwitch;
import io.github.dsheirer.gui.control.IntegerTextField;
import io.github.dsheirer.playlist.PlaylistManager;
import javafx.geometry.HPos;
@@ -113,6 +114,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.setHgap(5);
Label formatLabel = new Label("Format");
formatLabel.setLabelFor(getFormatField());
GridPane.setHalignment(formatLabel, HPos.RIGHT);
GridPane.setConstraints(formatLabel, 0, 0);
mEditorPane.getChildren().add(formatLabel);
@@ -122,6 +124,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getFormatField());
Label enabledLabel = new Label("Enabled");
enabledLabel.setLabelFor(getEnabledSwitch());
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
GridPane.setConstraints(enabledLabel, 2, 0);
mEditorPane.getChildren().add(enabledLabel);
@@ -130,6 +133,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getEnabledSwitch());
Label systemLabel = new Label("Name");
systemLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, 1);
mEditorPane.getChildren().add(systemLabel);
@@ -138,6 +142,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getNameTextField());
Label publicLabel = new Label("Public");
publicLabel.setLabelFor(getPublicToggleSwitch());
GridPane.setHalignment(publicLabel, HPos.RIGHT);
GridPane.setConstraints(publicLabel, 2, 1);
mEditorPane.getChildren().add(publicLabel);
@@ -146,6 +151,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getPublicToggleSwitch());
Label hostLabel = new Label("Server");
hostLabel.setLabelFor(getHostTextField());
GridPane.setHalignment(hostLabel, HPos.RIGHT);
GridPane.setConstraints(hostLabel, 0, 2);
mEditorPane.getChildren().add(hostLabel);
@@ -154,6 +160,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getHostTextField());
Label portLabel = new Label("Port");
portLabel.setLabelFor(getPortTextField());
GridPane.setHalignment(portLabel, HPos.RIGHT);
GridPane.setConstraints(portLabel, 2, 2);
mEditorPane.getChildren().add(portLabel);
@@ -162,6 +169,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getPortTextField());
Label userIdLabel = new Label("User ID");
userIdLabel.setLabelFor(getUserIdTextField());
GridPane.setHalignment(userIdLabel, HPos.RIGHT);
GridPane.setConstraints(userIdLabel, 0, 3);
mEditorPane.getChildren().add(userIdLabel);
@@ -170,6 +178,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getUserIdTextField());
Label streamIdLabel = new Label("Stream ID");
streamIdLabel.setLabelFor(getStreamIdTextField());
GridPane.setHalignment(streamIdLabel, HPos.RIGHT);
GridPane.setConstraints(streamIdLabel, 2, 3);
mEditorPane.getChildren().add(streamIdLabel);
@@ -178,6 +187,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getStreamIdTextField());
Label passwordLabel = new Label("Password");
setPasswordLabel(passwordLabel);
GridPane.setHalignment(passwordLabel, HPos.RIGHT);
GridPane.setConstraints(passwordLabel, 0, 4);
mEditorPane.getChildren().add(passwordLabel);
@@ -190,6 +200,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getShowPasswordCheckBox());
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
maxAgeLabel.setLabelFor(getMaxAgeTextField());
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
GridPane.setConstraints(maxAgeLabel, 0, 5);
mEditorPane.getChildren().add(maxAgeLabel);
@@ -198,6 +209,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getMaxAgeTextField());
Label delayLabel = new Label("Delay (seconds)");
delayLabel.setLabelFor(getDelayTextField());
GridPane.setHalignment(delayLabel, HPos.RIGHT);
GridPane.setConstraints(delayLabel, 2, 5);
mEditorPane.getChildren().add(delayLabel);
@@ -206,6 +218,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getDelayTextField());
Label descriptionLabel = new Label("Description");
descriptionLabel.setLabelFor(getUrlTextField());
GridPane.setHalignment(descriptionLabel, HPos.RIGHT);
GridPane.setConstraints(descriptionLabel, 0, 6);
mEditorPane.getChildren().add(descriptionLabel);
@@ -214,6 +227,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
mEditorPane.getChildren().add(getUrlTextField());
Label genreLabel = new Label("Genre");
genreLabel.setLabelFor(getGenreTextField());
GridPane.setHalignment(genreLabel, HPos.RIGHT);
GridPane.setConstraints(genreLabel, 0, 7);
mEditorPane.getChildren().add(genreLabel);
@@ -277,7 +291,7 @@ public class ShoutcastV2StreamEditor extends AbstractStreamEditor<ShoutcastV2Con
{
if(mPublicToggleSwitch == null)
{
mPublicToggleSwitch = new ToggleSwitch();
mPublicToggleSwitch = new AccessibleToggleSwitch();
mPublicToggleSwitch.setDisable(true);
mPublicToggleSwitch.selectedProperty().addListener((observable, oldValue, newValue) -> modifiedProperty().set(true));
}

View File

@@ -39,6 +39,7 @@ import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.Tooltip;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
@@ -153,6 +154,7 @@ public class StreamAliasSelectionEditor extends VBox
mSearchBox.setSpacing(5);
Label searchLabel = new Label("Search:");
searchLabel.setLabelFor(getSearchField());
searchLabel.setAlignment(Pos.CENTER_RIGHT);
mSearchBox.getChildren().addAll(searchLabel, getSearchField());
}
@@ -212,6 +214,7 @@ public class StreamAliasSelectionEditor extends VBox
if(mAvailableAliasTableView == null)
{
mAvailableAliasTableView = new TableView<>();
mAvailableAliasTableView.setAccessibleText("Available aliases");
mAvailableAliasTableView.setMaxHeight(Double.MAX_VALUE);
mAvailableAliasTableView.setDisable(true);
mAvailableAliasTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@@ -256,6 +259,7 @@ public class StreamAliasSelectionEditor extends VBox
if(mSelectedAliasTableView == null)
{
mSelectedAliasTableView = new TableView<>();
mSelectedAliasTableView.setAccessibleText("Aliases selected for this stream");
mSelectedAliasTableView.setMaxHeight(Double.MAX_VALUE);
mSelectedAliasTableView.setDisable(true);
mSelectedAliasTableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
@@ -303,6 +307,8 @@ public class StreamAliasSelectionEditor extends VBox
mAddButton.setDisable(true);
mAddButton.setMaxWidth(Double.MAX_VALUE);
mAddButton.setGraphic(new IconNode(FontAwesome.ANGLE_RIGHT));
mAddButton.setAccessibleText("Add selected alias to stream");
mAddButton.setTooltip(new Tooltip("Add selected alias to stream"));
mAddButton.setAlignment(Pos.CENTER);
mAddButton.setOnAction(event -> {
Alias selectedAlias = getAvailableAliasTableView().getSelectionModel().getSelectedItem();
@@ -327,6 +333,8 @@ public class StreamAliasSelectionEditor extends VBox
mAddAllButton.setDisable(true);
mAddAllButton.setMaxWidth(Double.MAX_VALUE);
mAddAllButton.setGraphic(new IconNode(FontAwesome.ANGLE_DOUBLE_RIGHT));
mAddAllButton.setAccessibleText("Add all selected aliases to stream");
mAddAllButton.setTooltip(new Tooltip("Add all selected aliases to stream"));
mAddAllButton.setAlignment(Pos.CENTER);
mAddAllButton.setOnAction(new EventHandler<ActionEvent>()
{
@@ -361,6 +369,8 @@ public class StreamAliasSelectionEditor extends VBox
mRemoveButton.setDisable(true);
mRemoveButton.setMaxWidth(Double.MAX_VALUE);
mRemoveButton.setGraphic(new IconNode(FontAwesome.ANGLE_LEFT));
mRemoveButton.setAccessibleText("Remove selected alias from stream");
mRemoveButton.setTooltip(new Tooltip("Remove selected alias from stream"));
mRemoveButton.setAlignment(Pos.CENTER);
mRemoveButton.setOnAction(event -> {
Alias selectedAlias = getSelectedAliasTableView().getSelectionModel().getSelectedItem();
@@ -385,6 +395,8 @@ public class StreamAliasSelectionEditor extends VBox
mRemoveAllButton.setDisable(true);
mRemoveAllButton.setMaxWidth(Double.MAX_VALUE);
mRemoveAllButton.setGraphic(new IconNode(FontAwesome.ANGLE_DOUBLE_LEFT));
mRemoveAllButton.setAccessibleText("Remove all selected aliases from stream");
mRemoveAllButton.setTooltip(new Tooltip("Remove all selected aliases from stream"));
mRemoveAllButton.setAlignment(Pos.CENTER);
mRemoveAllButton.setOnAction(event -> {
List<Alias> selectedAliases =

View File

@@ -396,6 +396,7 @@ public class StreamingEditor extends SplitPane
if(mConfiguredBroadcastTableView == null)
{
mConfiguredBroadcastTableView = new TableView<>();
mConfiguredBroadcastTableView.setAccessibleText("Streams");
mConfiguredBroadcastTableView.setPlaceholder(new Label("Click the New button to create a new " +
"audio streaming configuration"));
mConfiguredBroadcastTableView.setItems(mPlaylistManager.getBroadcastModel().getConfiguredBroadcasts());
@@ -414,12 +415,14 @@ public class StreamingEditor extends SplitPane
if(empty || item == null || !item)
{
setGraphic(null);
setAccessibleText(empty ? null : "No");
}
else
{
IconNode iconNode = new IconNode(FontAwesome.CHECK);
iconNode.setFill(Color.GREEN);
setGraphic(iconNode);
setAccessibleText("Yes");
}
}
};

View File

@@ -72,6 +72,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.setHgap(5);
Label formatLabel = new Label("Format");
formatLabel.setLabelFor(getFormatField());
GridPane.setHalignment(formatLabel, HPos.RIGHT);
GridPane.setConstraints(formatLabel, 0, 0);
mEditorPane.getChildren().add(formatLabel);
@@ -81,6 +82,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.getChildren().add(getFormatField());
Label enabledLabel = new Label("Enabled");
enabledLabel.setLabelFor(getEnabledSwitch());
GridPane.setHalignment(enabledLabel, HPos.RIGHT);
GridPane.setConstraints(enabledLabel, 2, 0);
mEditorPane.getChildren().add(enabledLabel);
@@ -89,6 +91,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.getChildren().add(getEnabledSwitch());
Label systemLabel = new Label("Name");
systemLabel.setLabelFor(getNameTextField());
GridPane.setHalignment(systemLabel, HPos.RIGHT);
GridPane.setConstraints(systemLabel, 0, 1);
mEditorPane.getChildren().add(systemLabel);
@@ -97,6 +100,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.getChildren().add(getNameTextField());
Label hostLabel = new Label("Host");
hostLabel.setLabelFor(getHostTextField());
GridPane.setHalignment(hostLabel, HPos.RIGHT);
GridPane.setConstraints(hostLabel, 0, 2);
mEditorPane.getChildren().add(hostLabel);
@@ -105,6 +109,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.getChildren().add(getHostTextField());
Label portLabel = new Label("Port");
portLabel.setLabelFor(getPortTextField());
GridPane.setHalignment(portLabel, HPos.RIGHT);
GridPane.setConstraints(portLabel, 2, 2);
mEditorPane.getChildren().add(portLabel);
@@ -113,6 +118,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.getChildren().add(getPortTextField());
Label passwordLabel = new Label("Password");
setPasswordLabel(passwordLabel);
GridPane.setHalignment(passwordLabel, HPos.RIGHT);
GridPane.setConstraints(passwordLabel, 0, 3);
mEditorPane.getChildren().add(passwordLabel);
@@ -121,6 +127,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.getChildren().add(getMaskedPasswordTextField());
Label maxAgeLabel = new Label("Max Recording Age (seconds)");
maxAgeLabel.setLabelFor(getMaxAgeTextField());
GridPane.setHalignment(maxAgeLabel, HPos.RIGHT);
GridPane.setConstraints(maxAgeLabel, 0, 4);
mEditorPane.getChildren().add(maxAgeLabel);
@@ -129,6 +136,7 @@ public class UnknownStreamEditor extends AbstractStreamEditor<BroadcastConfigura
mEditorPane.getChildren().add(getMaxAgeTextField());
Label delayLabel = new Label("Delay (seconds)");
delayLabel.setLabelFor(getDelayTextField());
GridPane.setHalignment(delayLabel, HPos.RIGHT);
GridPane.setConstraints(delayLabel, 2, 4);
mEditorPane.getChildren().add(delayLabel);