Add a few predicates and actions for the event system

This commit is contained in:
0xboobface 2018-12-08 13:08:20 +01:00
parent f7dfabb898
commit 1fc16a0d41
14 changed files with 406 additions and 51 deletions

View File

@ -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<Site> 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");

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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() {

View File

@ -0,0 +1,16 @@
package ctbrec.event;
import java.util.function.Consumer;
public abstract class Action implements Consumer<Event> {
protected String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -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();

View File

@ -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<Predicate<Event>> predicates = new ArrayList<>();
private Consumer<Event> action;
private List<Consumer<Event>> actions;
@SafeVarargs
public EventReaction(Consumer<Event> action, Predicate<Event>... predicates) {
this.action = action;
public EventHandler(Consumer<Event> action, Predicate<Event>... predicates) {
this(Collections.singletonList(action), predicates);
}
@SafeVarargs
public EventHandler(List<Consumer<Event>> actions, Predicate<Event>... predicates) {
this.actions = actions;
for (Predicate<Event> predicate : predicates) {
this.predicates.add(predicate);
}
@ -26,7 +32,9 @@ public class EventReaction {
}
}
if(matches) {
action.accept(evt);
for (Consumer<Event> action : actions) {
action.accept(evt);
}
}
}
}

View File

@ -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<PredicateConfiguration> predicates = new ArrayList<>();
private List<ActionConfiguration> 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<PredicateConfiguration> getPredicates() {
return predicates;
}
public void setPredicates(List<PredicateConfiguration> predicates) {
this.predicates = predicates;
}
public List<ActionConfiguration> getActions() {
return actions;
}
public void setActions(List<ActionConfiguration> actions) {
this.actions = actions;
}
public class PredicateConfiguration {
private String type;
private Map<String, Object> configuration = new HashMap<>();
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<String, Object> getConfiguration() {
return configuration;
}
public void setConfiguration(Map<String, Object> configuration) {
this.configuration = configuration;
}
}
public class ActionConfiguration {
private String type;
private Map<String, Object> configuration = new HashMap<>();
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public Map<String, Object> getConfiguration() {
return configuration;
}
public void setConfiguration(Map<String, Object> configuration) {
this.configuration = configuration;
}
}
}

View File

@ -4,11 +4,11 @@ import java.util.function.Predicate;
import ctbrec.event.Event.Type;
public class TypePredicate implements Predicate<Event> {
public class EventTypePredicate implements Predicate<Event> {
private Type type;
private TypePredicate(Type type) {
private EventTypePredicate(Type type) {
this.type = type;
}
@ -17,7 +17,7 @@ public class TypePredicate implements Predicate<Event> {
return evt.getType() == type;
}
public static TypePredicate of(Type type) {
return new TypePredicate(type);
public static EventTypePredicate of(Type type) {
return new EventTypePredicate(type);
}
}

View File

@ -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));
}
}

View File

@ -0,0 +1,30 @@
package ctbrec.event;
import java.util.Objects;
import java.util.function.Predicate;
import ctbrec.Model;
public class ModelPredicate implements Predicate<Event> {
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);
}
}

View File

@ -0,0 +1,29 @@
package ctbrec.event;
import java.util.function.Predicate;
import ctbrec.Model;
public class ModelStatePredicate implements Predicate<Event> {
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);
}
}