From 1fc16a0d4122ed8c04bc1c65c963ccd4343c7aca Mon Sep 17 00:00:00 2001 From: 0xboobface <0xboobface@gmail.com> Date: Sat, 8 Dec 2018 13:08:20 +0100 Subject: [PATCH] Add a few predicates and actions for the event system --- .../java/ctbrec/ui/CamrecApplication.java | 29 +++--- .../main/java/ctbrec/ui/controls/Wizard.java | 74 +++++++++++++++ .../ui/event/ModelStateNotification.java | 23 +++++ .../main/java/ctbrec/ui/event/PlaySound.java | 23 +++++ .../ui/settings/ActionSettingsPanel.java | 82 +++++++++++++++-- .../java/ctbrec/ui/settings/SettingsTab.java | 4 +- common/src/main/java/ctbrec/event/Action.java | 16 ++++ common/src/main/java/ctbrec/event/Event.java | 17 +++- .../{EventReaction.java => EventHandler.java} | 18 ++-- .../event/EventHandlerConfiguration.java | 89 +++++++++++++++++++ ...Predicate.java => EventTypePredicate.java} | 8 +- .../main/java/ctbrec/event/LogReaction.java | 15 ---- .../java/ctbrec/event/ModelPredicate.java | 30 +++++++ .../ctbrec/event/ModelStatePredicate.java | 29 ++++++ 14 files changed, 406 insertions(+), 51 deletions(-) create mode 100644 client/src/main/java/ctbrec/ui/controls/Wizard.java create mode 100644 client/src/main/java/ctbrec/ui/event/ModelStateNotification.java create mode 100644 client/src/main/java/ctbrec/ui/event/PlaySound.java create mode 100644 common/src/main/java/ctbrec/event/Action.java rename common/src/main/java/ctbrec/event/{EventReaction.java => EventHandler.java} (55%) create mode 100644 common/src/main/java/ctbrec/event/EventHandlerConfiguration.java rename common/src/main/java/ctbrec/event/{TypePredicate.java => EventTypePredicate.java} (55%) delete mode 100644 common/src/main/java/ctbrec/event/LogReaction.java create mode 100644 common/src/main/java/ctbrec/event/ModelPredicate.java create mode 100644 common/src/main/java/ctbrec/event/ModelStatePredicate.java diff --git a/client/src/main/java/ctbrec/ui/CamrecApplication.java b/client/src/main/java/ctbrec/ui/CamrecApplication.java index 70bbf4bd..df11cabc 100644 --- a/client/src/main/java/ctbrec/ui/CamrecApplication.java +++ b/client/src/main/java/ctbrec/ui/CamrecApplication.java @@ -26,12 +26,10 @@ import com.squareup.moshi.Types; import ctbrec.Config; import ctbrec.Model; -import ctbrec.OS; import ctbrec.StringUtil; import ctbrec.Version; import ctbrec.event.Event; import ctbrec.event.EventBusHolder; -import ctbrec.event.LogReaction; import ctbrec.event.ModelStateChangedEvent; import ctbrec.io.HttpClient; import ctbrec.recorder.LocalRecorder; @@ -73,7 +71,7 @@ public class CamrecApplication extends Application { private TabPane rootPane = new TabPane(); private List sites = new ArrayList<>(); public static HttpClient httpClient; - + public static String title; @Override public void start(Stage primaryStage) throws Exception { @@ -114,7 +112,8 @@ public class CamrecApplication extends Application { private void createGui(Stage primaryStage) throws IOException { LOG.debug("Creating GUI"); - primaryStage.setTitle("CTB Recorder " + getVersion()); + CamrecApplication.title = "CTB Recorder " + getVersion(); + primaryStage.setTitle(title); InputStream icon = getClass().getResourceAsStream("/icon.png"); primaryStage.getIcons().add(new Image(icon)); int windowWidth = Config.getInstance().getSettings().windowWidth; @@ -230,10 +229,11 @@ public class CamrecApplication extends Application { if (e.getType() == MODEL_STATUS_CHANGED) { ModelStateChangedEvent evt = (ModelStateChangedEvent) e; Model model = evt.getModel(); - if (evt.getNewState() == ONLINE) { + if (evt.getNewState() == ONLINE && primaryStage != null && primaryStage.getTitle() != null) { String header = "Model Online"; String msg = model.getDisplayName() + " is now online"; - OS.notification(primaryStage.getTitle(), header, msg); + LOG.debug(msg); + //OS.notification(primaryStage.getTitle(), header, msg); } } } catch (Exception e1) { @@ -242,13 +242,16 @@ public class CamrecApplication extends Application { } }); - EventBusHolder.BUS.register(new Object() { - LogReaction reaction = new LogReaction(); - @Subscribe - public void modelEvent(Event e) { - reaction.reactToEvent(e); - } - }); + // EventBusHolder.BUS.register(new Object() { + // URL url = CamrecApplication.class.getResource("/Oxygen-Im-Highlight-Msg.mp3"); + // PlaySound playSound = new PlaySound(url); + // EventHandler reaction = new EventHandler(playSound); + // // LogReaction reaction = new LogReaction(); + // @Subscribe + // public void modelEvent(Event e) { + // reaction.reactToEvent(e); + // } + // }); LOG.debug("Alert System registered"); diff --git a/client/src/main/java/ctbrec/ui/controls/Wizard.java b/client/src/main/java/ctbrec/ui/controls/Wizard.java new file mode 100644 index 00000000..bc653e2e --- /dev/null +++ b/client/src/main/java/ctbrec/ui/controls/Wizard.java @@ -0,0 +1,74 @@ +package ctbrec.ui.controls; + +import javafx.geometry.Insets; +import javafx.geometry.Pos; +import javafx.scene.control.Button; +import javafx.scene.layout.BorderPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.scene.layout.StackPane; +import javafx.stage.Stage; + +public class Wizard extends BorderPane { + + private Pane[] pages; + private StackPane stack; + private Stage stage; + private int page = 0; + private Button next; + private Button prev; + private Button finish; + + public Wizard(Stage stage, Pane... pages) { + this.stage = stage; + this.pages = pages; + + if (pages.length == 0) { + throw new IllegalArgumentException("Provide at least one page"); + } + + createUi(); + } + + private void createUi() { + stack = new StackPane(); + setCenter(stack); + + next = new Button("Next"); + next.setOnAction(evt -> nextPage()); + prev = new Button("Prev"); + prev.setOnAction(evt -> prevPage()); + Button cancel = new Button("Cancel"); + cancel.setOnAction(evt -> stage.close()); + finish = new Button("Finish"); + HBox buttons = new HBox(5, prev, next, cancel, finish); + buttons.setAlignment(Pos.BASELINE_RIGHT); + setBottom(buttons); + BorderPane.setMargin(buttons, new Insets(5)); + + if (pages.length != 0) { + stack.getChildren().add(pages[0]); + } + setButtonStates(); + } + + private void prevPage() { + page = Math.max(0, --page); + stack.getChildren().clear(); + stack.getChildren().add(pages[page]); + setButtonStates(); + } + + private void nextPage() { + page = Math.min(pages.length - 1, ++page); + stack.getChildren().clear(); + stack.getChildren().add(pages[page]); + setButtonStates(); + } + + private void setButtonStates() { + prev.setDisable(page == 0); + next.setDisable(page == pages.length - 1); + finish.setDisable(page != pages.length - 1); + } +} diff --git a/client/src/main/java/ctbrec/ui/event/ModelStateNotification.java b/client/src/main/java/ctbrec/ui/event/ModelStateNotification.java new file mode 100644 index 00000000..a831b4e3 --- /dev/null +++ b/client/src/main/java/ctbrec/ui/event/ModelStateNotification.java @@ -0,0 +1,23 @@ +package ctbrec.ui.event; + +import ctbrec.OS; +import ctbrec.event.Action; +import ctbrec.event.Event; +import ctbrec.ui.CamrecApplication; + +public class ModelStateNotification extends Action { + + private String header; + private String msg; + + public ModelStateNotification(String header, String msg) { + this.header = header; + this.msg = msg; + name = "show notification"; + } + + @Override + public void accept(Event evt) { + OS.notification(CamrecApplication.title, header, msg); + } +} diff --git a/client/src/main/java/ctbrec/ui/event/PlaySound.java b/client/src/main/java/ctbrec/ui/event/PlaySound.java new file mode 100644 index 00000000..7464bebb --- /dev/null +++ b/client/src/main/java/ctbrec/ui/event/PlaySound.java @@ -0,0 +1,23 @@ +package ctbrec.ui.event; + +import java.net.URL; + +import ctbrec.event.Action; +import ctbrec.event.Event; +import javafx.scene.media.AudioClip; + +public class PlaySound extends Action { + + private URL url; + + public PlaySound(URL url) { + this.url = url; + name = "play sound"; + } + + @Override + public void accept(Event evt) { + AudioClip clip = new AudioClip(url.toString()); + clip.play(); + } +} diff --git a/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java b/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java index 08e57242..250bce86 100644 --- a/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java +++ b/client/src/main/java/ctbrec/ui/settings/ActionSettingsPanel.java @@ -1,30 +1,94 @@ package ctbrec.ui.settings; -import ctbrec.event.Event.Type; +import java.io.InputStream; + +import ctbrec.event.EventHandlerConfiguration; +import ctbrec.ui.controls.Wizard; +import javafx.event.ActionEvent; +import javafx.geometry.Insets; +import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; +import javafx.scene.control.ScrollPane; +import javafx.scene.control.TableView; +import javafx.scene.control.TextField; import javafx.scene.control.TitledPane; +import javafx.scene.image.Image; +import javafx.scene.layout.Border; +import javafx.scene.layout.BorderPane; import javafx.scene.layout.GridPane; +import javafx.scene.layout.HBox; +import javafx.scene.layout.Pane; +import javafx.stage.Stage; public class ActionSettingsPanel extends TitledPane { + private TableView actionTable; + public ActionSettingsPanel(SettingsTab settingsTab) { - setText("Actions"); + setText("Events & Actions"); setExpanded(true); setCollapsible(false); createGui(); } private void createGui() { - GridPane mainLayout = SettingsTab.createGridLayout(); + BorderPane mainLayout = new BorderPane(); setContent(mainLayout); + actionTable = createActionTable(); + actionTable.setPrefSize(300, 200); + ScrollPane scrollPane = new ScrollPane(actionTable); + scrollPane.setFitToHeight(true); + scrollPane.setFitToWidth(true); + scrollPane.setBorder(Border.EMPTY); + mainLayout.setCenter(scrollPane); + BorderPane.setMargin(scrollPane, new Insets(5)); + + Button add = new Button("Add"); + add.setOnAction(this::add); + Button delete = new Button("Delete"); + delete.setOnAction(this::delete); + delete.setDisable(true); + HBox buttons = new HBox(10, add, delete); + mainLayout.setBottom(buttons); + BorderPane.setMargin(buttons, new Insets(5)); + } + + private void add(ActionEvent evt) { + EventHandlerConfiguration config = new EventHandlerConfiguration(); + Pane namePane = createNamePane(config); + GridPane pane2 = SettingsTab.createGridLayout(); + pane2.add(new Label("Pane 2"), 0, 0); + GridPane pane3 = SettingsTab.createGridLayout(); + pane3.add(new Label("Pane 3"), 0, 0); + Stage dialog = new Stage(); + dialog.setTitle("New Action"); + InputStream icon = getClass().getResourceAsStream("/icon.png"); + dialog.getIcons().add(new Image(icon)); + Wizard root = new Wizard(dialog, namePane, pane2, pane3); + Scene scene = new Scene(root, 640, 480); + scene.getStylesheets().addAll(getScene().getStylesheets()); + dialog.setScene(scene); + dialog.showAndWait(); + } + + private void delete(ActionEvent evt) { + + } + + private Pane createNamePane(EventHandlerConfiguration config) { + GridPane layout = SettingsTab.createGridLayout(); int row = 0; - for (Type type : Type.values()) { - Label l = new Label(type.name()); - mainLayout.add(l, 0, row); - Button b = new Button("Configure"); - mainLayout.add(b, 1, row++); - } + layout.add(new Label("Name"), 0, row); + TextField name = new TextField(); + layout.add(name, 1, row); + return layout; + } + + + private TableView createActionTable() { + TableView view = new TableView(); + return view; } } diff --git a/client/src/main/java/ctbrec/ui/settings/SettingsTab.java b/client/src/main/java/ctbrec/ui/settings/SettingsTab.java index 0115f0a4..b31e9202 100644 --- a/client/src/main/java/ctbrec/ui/settings/SettingsTab.java +++ b/client/src/main/java/ctbrec/ui/settings/SettingsTab.java @@ -130,7 +130,8 @@ public class SettingsTab extends Tab implements TabSelectionListener { //right side rightSide.getChildren().add(siteConfigAccordion); - rightSide.getChildren().add(new ActionSettingsPanel(this)); + ActionSettingsPanel actions = new ActionSettingsPanel(this); + rightSide.getChildren().add(actions); proxySettingsPane = new ProxySettingsPane(this); rightSide.getChildren().add(proxySettingsPane); for (int i = 0; i < sites.size(); i++) { @@ -141,7 +142,6 @@ public class SettingsTab extends Tab implements TabSelectionListener { siteConfigAccordion.getPanes().add(pane); } } - siteConfigAccordion.setExpandedPane(siteConfigAccordion.getPanes().get(0)); } private Node createRecordLocationPanel() { diff --git a/common/src/main/java/ctbrec/event/Action.java b/common/src/main/java/ctbrec/event/Action.java new file mode 100644 index 00000000..a71b99af --- /dev/null +++ b/common/src/main/java/ctbrec/event/Action.java @@ -0,0 +1,16 @@ +package ctbrec.event; + +import java.util.function.Consumer; + +public abstract class Action implements Consumer { + + protected String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/common/src/main/java/ctbrec/event/Event.java b/common/src/main/java/ctbrec/event/Event.java index a5477e6d..de8393ee 100644 --- a/common/src/main/java/ctbrec/event/Event.java +++ b/common/src/main/java/ctbrec/event/Event.java @@ -7,18 +7,29 @@ public abstract class Event { * This event is fired every time the OnlineMonitor sees a model online * It is also fired, if the model was online before. You can see it as a "still online ping". */ - MODEL_ONLINE, + MODEL_ONLINE("Model is online"), /** * This event is fired whenever the model's online state (Model.STATUS) changes. */ - MODEL_STATUS_CHANGED, + MODEL_STATUS_CHANGED("Model status changed"), /** * This event is fired whenever the state of a recording changes. */ - RECORDING_STATUS_CHANGED + RECORDING_STATUS_CHANGED("Recording status changed"); + + private String desc; + + Type(String desc) { + this.desc = desc; + } + + @Override + public String toString() { + return desc; + } } public abstract Type getType(); diff --git a/common/src/main/java/ctbrec/event/EventReaction.java b/common/src/main/java/ctbrec/event/EventHandler.java similarity index 55% rename from common/src/main/java/ctbrec/event/EventReaction.java rename to common/src/main/java/ctbrec/event/EventHandler.java index 8ee2df81..6621a2d8 100644 --- a/common/src/main/java/ctbrec/event/EventReaction.java +++ b/common/src/main/java/ctbrec/event/EventHandler.java @@ -1,18 +1,24 @@ package ctbrec.event; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.function.Consumer; import java.util.function.Predicate; -public class EventReaction { +public class EventHandler { private List> predicates = new ArrayList<>(); - private Consumer action; + private List> actions; @SafeVarargs - public EventReaction(Consumer action, Predicate... predicates) { - this.action = action; + public EventHandler(Consumer action, Predicate... predicates) { + this(Collections.singletonList(action), predicates); + } + + @SafeVarargs + public EventHandler(List> actions, Predicate... predicates) { + this.actions = actions; for (Predicate predicate : predicates) { this.predicates.add(predicate); } @@ -26,7 +32,9 @@ public class EventReaction { } } if(matches) { - action.accept(evt); + for (Consumer action : actions) { + action.accept(evt); + } } } } diff --git a/common/src/main/java/ctbrec/event/EventHandlerConfiguration.java b/common/src/main/java/ctbrec/event/EventHandlerConfiguration.java new file mode 100644 index 00000000..8b2f3b15 --- /dev/null +++ b/common/src/main/java/ctbrec/event/EventHandlerConfiguration.java @@ -0,0 +1,89 @@ +package ctbrec.event; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class EventHandlerConfiguration { + + private String name; + private Event.Type event; + private List predicates = new ArrayList<>(); + private List actions = new ArrayList<>(); + + public Event.Type getEvent() { + return event; + } + + public void setEvent(Event.Type event) { + this.event = event; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getPredicates() { + return predicates; + } + + public void setPredicates(List predicates) { + this.predicates = predicates; + } + + public List getActions() { + return actions; + } + + public void setActions(List actions) { + this.actions = actions; + } + + public class PredicateConfiguration { + private String type; + private Map configuration = new HashMap<>(); + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map getConfiguration() { + return configuration; + } + + public void setConfiguration(Map configuration) { + this.configuration = configuration; + } + + } + + public class ActionConfiguration { + private String type; + private Map configuration = new HashMap<>(); + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public Map getConfiguration() { + return configuration; + } + + public void setConfiguration(Map configuration) { + this.configuration = configuration; + } + } +} diff --git a/common/src/main/java/ctbrec/event/TypePredicate.java b/common/src/main/java/ctbrec/event/EventTypePredicate.java similarity index 55% rename from common/src/main/java/ctbrec/event/TypePredicate.java rename to common/src/main/java/ctbrec/event/EventTypePredicate.java index e84be4df..63bb3965 100644 --- a/common/src/main/java/ctbrec/event/TypePredicate.java +++ b/common/src/main/java/ctbrec/event/EventTypePredicate.java @@ -4,11 +4,11 @@ import java.util.function.Predicate; import ctbrec.event.Event.Type; -public class TypePredicate implements Predicate { +public class EventTypePredicate implements Predicate { private Type type; - private TypePredicate(Type type) { + private EventTypePredicate(Type type) { this.type = type; } @@ -17,7 +17,7 @@ public class TypePredicate implements Predicate { return evt.getType() == type; } - public static TypePredicate of(Type type) { - return new TypePredicate(type); + public static EventTypePredicate of(Type type) { + return new EventTypePredicate(type); } } diff --git a/common/src/main/java/ctbrec/event/LogReaction.java b/common/src/main/java/ctbrec/event/LogReaction.java deleted file mode 100644 index ec5444f7..00000000 --- a/common/src/main/java/ctbrec/event/LogReaction.java +++ /dev/null @@ -1,15 +0,0 @@ -package ctbrec.event; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class LogReaction extends EventReaction { - - private static final transient Logger LOG = LoggerFactory.getLogger(LogReaction.class); - - public LogReaction() { - super(evt -> { - LOG.debug("LogReaction: {}", evt); - }, TypePredicate.of(Event.Type.RECORDING_STATUS_CHANGED)); - } -} diff --git a/common/src/main/java/ctbrec/event/ModelPredicate.java b/common/src/main/java/ctbrec/event/ModelPredicate.java new file mode 100644 index 00000000..e23c902c --- /dev/null +++ b/common/src/main/java/ctbrec/event/ModelPredicate.java @@ -0,0 +1,30 @@ +package ctbrec.event; + +import java.util.Objects; +import java.util.function.Predicate; + +import ctbrec.Model; + +public class ModelPredicate implements Predicate { + + private Model model; + + private ModelPredicate(Model model) { + this.model = model; + } + + @Override + public boolean test(Event evt) { + if(evt instanceof AbstractModelEvent) { + AbstractModelEvent modelEvent = (AbstractModelEvent) evt; + Model other = modelEvent.getModel(); + return Objects.equals(model, other); + } else { + return false; + } + } + + public static ModelPredicate of(Model model) { + return new ModelPredicate(model); + } +} diff --git a/common/src/main/java/ctbrec/event/ModelStatePredicate.java b/common/src/main/java/ctbrec/event/ModelStatePredicate.java new file mode 100644 index 00000000..3dad100e --- /dev/null +++ b/common/src/main/java/ctbrec/event/ModelStatePredicate.java @@ -0,0 +1,29 @@ +package ctbrec.event; + +import java.util.function.Predicate; + +import ctbrec.Model; + +public class ModelStatePredicate implements Predicate { + + private Model.State state; + + private ModelStatePredicate(Model.State state) { + this.state = state; + } + + @Override + public boolean test(Event evt) { + if(evt instanceof AbstractModelEvent) { + ModelStateChangedEvent modelEvent = (ModelStateChangedEvent) evt; + Model.State newState = modelEvent.getNewState(); + return newState == state; + } else { + return false; + } + } + + public static ModelStatePredicate of(Model.State state) { + return new ModelStatePredicate(state); + } +}