diff --git a/client/src/main/java/ctbrec/ui/event/PlaySound.java b/client/src/main/java/ctbrec/ui/event/PlaySound.java index a598652d..46f58b8b 100644 --- a/client/src/main/java/ctbrec/ui/event/PlaySound.java +++ b/client/src/main/java/ctbrec/ui/event/PlaySound.java @@ -1,35 +1,39 @@ package ctbrec.ui.event; -import java.io.File; -import java.net.URL; - import ctbrec.event.Action; import ctbrec.event.Event; import ctbrec.event.EventHandlerConfiguration.ActionConfiguration; import javafx.scene.media.AudioClip; +import java.io.File; +import java.net.URL; + public class PlaySound extends Action { private URL url; + private double volume = 1.0d; public PlaySound() { name = "play sound"; } - public PlaySound(URL url) { + public PlaySound(URL url, double volume) { this(); this.url = url; + this.volume = volume; } @Override public void accept(Event evt) { var clip = new AudioClip(url.toString()); + clip.setVolume(volume); clip.play(); } @Override public void configure(ActionConfiguration config) throws Exception { var file = new File((String) config.getConfiguration().get("file")); + volume = Double.parseDouble(String.valueOf(config.getConfiguration().getOrDefault("volume", "1.0"))); url = file.toURI().toURL(); } } diff --git a/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java b/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java index 5d479172..1089e0e1 100644 --- a/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java +++ b/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java @@ -1,38 +1,16 @@ package ctbrec.ui.settings; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.time.ZonedDateTime; -import java.time.format.DateTimeFormatter; -import java.time.format.FormatStyle; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - -import javafx.scene.control.*; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import ctbrec.Config; import ctbrec.Model; import ctbrec.Recording; import ctbrec.StringUtil; -import ctbrec.event.Event; -import ctbrec.event.EventBusHolder; -import ctbrec.event.EventHandler; -import ctbrec.event.EventHandlerConfiguration; +import ctbrec.event.*; import ctbrec.event.EventHandlerConfiguration.ActionConfiguration; import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration; -import ctbrec.event.ExecuteProgram; -import ctbrec.event.MatchAllPredicate; -import ctbrec.event.ModelPredicate; -import ctbrec.event.ModelStatePredicate; -import ctbrec.event.RecordingStatePredicate; import ctbrec.recorder.Recorder; import ctbrec.ui.CamrecApplication; import ctbrec.ui.DesktopIntegration; +import ctbrec.ui.controls.Dialogs; import ctbrec.ui.controls.FileSelectionBox; import ctbrec.ui.controls.ProgramSelectionBox; import ctbrec.ui.controls.Wizard; @@ -42,9 +20,11 @@ import javafx.collections.ListChangeListener; import javafx.event.ActionEvent; import javafx.geometry.Insets; import javafx.geometry.Orientation; +import javafx.geometry.Pos; import javafx.geometry.VPos; import javafx.scene.Node; import javafx.scene.Scene; +import javafx.scene.control.*; import javafx.scene.image.Image; import javafx.scene.layout.GridPane; import javafx.scene.layout.HBox; @@ -53,6 +33,21 @@ import javafx.scene.layout.Priority; import javafx.stage.Modality; import javafx.stage.Stage; import javafx.stage.Window; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; public class ActionSettingsPanel extends GridPane { private static final Logger LOG = LoggerFactory.getLogger(ActionSettingsPanel.class); @@ -65,6 +60,7 @@ public class ActionSettingsPanel extends GridPane { private final CheckBox playSound = new CheckBox("Play sound"); private final FileSelectionBox sound = new FileSelectionBox(); + private final Slider soundVolume = new Slider(0, 100, 100); private final CheckBox showNotification = new CheckBox("Notify me"); private final Button testNotification = new Button("Test"); private final ToggleButton toggleEvents = new ToggleButton(); @@ -142,7 +138,7 @@ public class ActionSettingsPanel extends GridPane { dialog.setScene(scene); centerOnParent(dialog); dialog.showAndWait(); - if(!root.isCancelled()) { + if (!root.isCancelled()) { createEventHandler(); } } @@ -151,46 +147,47 @@ public class ActionSettingsPanel extends GridPane { var config = new EventHandlerConfiguration(); config.setName(name.getText()); config.setEvent(event.getValue()); - if(event.getValue() == Event.Type.MODEL_STATUS_CHANGED) { + if (event.getValue() == Event.Type.MODEL_STATUS_CHANGED) { var pc = new PredicateConfiguration(); pc.setType(ModelStatePredicate.class.getName()); pc.getConfiguration().put("state", modelState.getValue().name()); pc.setName("state = " + modelState.getValue().toString()); config.getPredicates().add(pc); - } else if(event.getValue() == Event.Type.RECORDING_STATUS_CHANGED) { + } else if (event.getValue() == Event.Type.RECORDING_STATUS_CHANGED) { var pc = new PredicateConfiguration(); pc.setType(RecordingStatePredicate.class.getName()); pc.getConfiguration().put("state", recordingState.getValue().name()); pc.setName("state = " + recordingState.getValue().toString()); config.getPredicates().add(pc); - } else if(event.getValue() == Event.Type.NO_SPACE_LEFT) { + } else if (event.getValue() == Event.Type.NO_SPACE_LEFT) { var pc = new PredicateConfiguration(); pc.setType(MatchAllPredicate.class.getName()); pc.setName("no space left"); config.getPredicates().add(pc); } - if(!modelSelectionPane.isAllSelected()) { + if (!modelSelectionPane.isAllSelected()) { var pc = new PredicateConfiguration(); pc.setType(ModelPredicate.class.getName()); pc.setModels(modelSelectionPane.getSelectedItems()); pc.setName("model is one of:" + modelSelectionPane.getSelectedItems()); config.getPredicates().add(pc); } - if(showNotification.isSelected()) { + if (showNotification.isSelected()) { var ac = new ActionConfiguration(); ac.setType(ShowNotification.class.getName()); ac.setName("show notification"); config.getActions().add(ac); } - if(playSound.isSelected()) { + if (playSound.isSelected()) { var ac = new ActionConfiguration(); ac.setType(PlaySound.class.getName()); var file = new File(sound.fileProperty().get()); ac.getConfiguration().put("file", file.getAbsolutePath()); + ac.getConfiguration().put("volume", soundVolume.getValue() / 100); ac.setName("play " + file.getName()); config.getActions().add(ac); } - if(executeProgram.isSelected()) { + if (executeProgram.isSelected()) { var ac = new ActionConfiguration(); ac.setType(ExecuteProgram.class.getName()); var file = new File(program.fileProperty().get()); @@ -207,19 +204,19 @@ public class ActionSettingsPanel extends GridPane { } private void validateSettings() { - if(StringUtil.isBlank(name.getText())) { + if (StringUtil.isBlank(name.getText())) { throw new IllegalStateException("Name cannot be empty"); } - if(event.getValue() == Event.Type.MODEL_STATUS_CHANGED && modelState.getValue() == null) { + if (event.getValue() == Event.Type.MODEL_STATUS_CHANGED && modelState.getValue() == null) { throw new IllegalStateException("Select a state"); } - if(event.getValue() == Event.Type.RECORDING_STATUS_CHANGED && recordingState.getValue() == null) { + if (event.getValue() == Event.Type.RECORDING_STATUS_CHANGED && recordingState.getValue() == null) { throw new IllegalStateException("Select a state"); } - if(event.getValue() != Event.Type.NO_SPACE_LEFT && modelSelectionPane.getSelectedItems().isEmpty() && !modelSelectionPane.isAllSelected()) { + if (event.getValue() != Event.Type.NO_SPACE_LEFT && modelSelectionPane.getSelectedItems().isEmpty() && !modelSelectionPane.isAllSelected()) { throw new IllegalStateException("Select one or more models or tick off \"all\""); } - if(!(showNotification.isSelected() || playSound.isSelected() || executeProgram.isSelected())) { + if (!(showNotification.isSelected() || playSound.isSelected() || executeProgram.isSelected())) { throw new IllegalStateException("No action selected"); } } @@ -254,7 +251,7 @@ public class ActionSettingsPanel extends GridPane { event.getSelectionModel().selectedItemProperty().addListener((obs, oldV, newV) -> { var modelRelatedStuffDisabled = false; - if(newV == Event.Type.NO_SPACE_LEFT) { + if (newV == Event.Type.NO_SPACE_LEFT) { modelRelatedStuffDisabled = true; modelSelectionPane.selectAll(); } @@ -294,9 +291,20 @@ public class ActionSettingsPanel extends GridPane { }); testNotification.disableProperty().bind(showNotification.selectedProperty().not()); + HBox soundContainer = new HBox(); + soundContainer.setAlignment(Pos.CENTER_LEFT); + soundContainer.setSpacing(5); layout.add(playSound, 0, row); - layout.add(sound, 1, row++); + layout.add(soundContainer, 1, row++); + soundContainer.getChildren().add(soundVolume); + soundContainer.getChildren().add(sound); sound.disableProperty().bind(playSound.selectedProperty().not()); + soundVolume.setTooltip(new Tooltip("Volume")); + soundVolume.disableProperty().bind(playSound.selectedProperty().not()); + HBox.setHgrow(sound, Priority.ALWAYS); + Button soundTest = new Button("Test"); + soundTest.setOnAction(this::testSound); + soundContainer.getChildren().add(soundTest); layout.add(executeProgram, 0, row); layout.add(program, 1, row); @@ -304,11 +312,18 @@ public class ActionSettingsPanel extends GridPane { GridPane.setFillWidth(name, true); GridPane.setHgrow(name, Priority.ALWAYS); - GridPane.setFillWidth(sound, true); - return layout; } + private void testSound(ActionEvent actionEvent) { + try { + URL soundFileUrl = new File(sound.fileProperty().getValue()).toURI().toURL(); + new PlaySound(soundFileUrl, soundVolume.getValue() / 100).accept(null); + } catch (MalformedURLException e) { + Dialogs.showError(getScene(), "Error", e.getLocalizedMessage(), e); + } + } + private ListView createActionTable() { ListView view = new ListView<>(); view.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);