Add first configurable version of the notification system
This commit is contained in:
parent
be680a07f9
commit
888046676f
|
@ -1,9 +1,6 @@
|
|||
package ctbrec.ui;
|
||||
|
||||
|
||||
import static ctbrec.Model.State.*;
|
||||
import static ctbrec.event.Event.Type.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -19,18 +16,16 @@ import java.util.Objects;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.squareup.moshi.JsonAdapter;
|
||||
import com.squareup.moshi.Moshi;
|
||||
import com.squareup.moshi.Types;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.Version;
|
||||
import ctbrec.event.Event;
|
||||
import ctbrec.event.EventBusHolder;
|
||||
import ctbrec.event.ModelStateChangedEvent;
|
||||
import ctbrec.event.EventHandler;
|
||||
import ctbrec.event.EventHandlerConfiguration;
|
||||
import ctbrec.io.HttpClient;
|
||||
import ctbrec.recorder.LocalRecorder;
|
||||
import ctbrec.recorder.OnlineMonitor;
|
||||
|
@ -62,7 +57,6 @@ public class CamrecApplication extends Application {
|
|||
|
||||
static final transient Logger LOG = LoggerFactory.getLogger(CamrecApplication.class);
|
||||
|
||||
private Stage primaryStage;
|
||||
private Config config;
|
||||
private Recorder recorder;
|
||||
private OnlineMonitor onlineMonitor;
|
||||
|
@ -75,15 +69,14 @@ public class CamrecApplication extends Application {
|
|||
|
||||
@Override
|
||||
public void start(Stage primaryStage) throws Exception {
|
||||
this.primaryStage = primaryStage;
|
||||
logEnvironment();
|
||||
registerAlertSystem();
|
||||
sites.add(new BongaCams());
|
||||
sites.add(new Cam4());
|
||||
sites.add(new Camsoda());
|
||||
sites.add(new Chaturbate());
|
||||
sites.add(new MyFreeCams());
|
||||
loadConfig();
|
||||
registerAlertSystem();
|
||||
createHttpClient();
|
||||
hostServices = getHostServices();
|
||||
createRecorder();
|
||||
|
@ -101,7 +94,6 @@ public class CamrecApplication extends Application {
|
|||
}
|
||||
createGui(primaryStage);
|
||||
checkForUpdates();
|
||||
|
||||
}
|
||||
|
||||
private void logEnvironment() {
|
||||
|
@ -134,7 +126,7 @@ public class CamrecApplication extends Application {
|
|||
rootPane.getTabs().add(modelsTab);
|
||||
RecordingsTab recordingsTab = new RecordingsTab("Recordings", recorder, config, sites);
|
||||
rootPane.getTabs().add(recordingsTab);
|
||||
settingsTab = new SettingsTab(sites);
|
||||
settingsTab = new SettingsTab(sites, recorder);
|
||||
rootPane.getTabs().add(settingsTab);
|
||||
rootPane.getTabs().add(new DonateTabFx());
|
||||
|
||||
|
@ -222,38 +214,11 @@ public class CamrecApplication extends Application {
|
|||
// } catch (InterruptedException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
EventBusHolder.BUS.register(new Object() {
|
||||
@Subscribe
|
||||
public void modelEvent(Event e) {
|
||||
try {
|
||||
if (e.getType() == MODEL_STATUS_CHANGED) {
|
||||
ModelStateChangedEvent evt = (ModelStateChangedEvent) e;
|
||||
Model model = evt.getModel();
|
||||
if (evt.getNewState() == ONLINE && primaryStage != null && primaryStage.getTitle() != null) {
|
||||
String header = "Model Online";
|
||||
String msg = model.getDisplayName() + " is now online";
|
||||
LOG.debug(msg);
|
||||
//OS.notification(primaryStage.getTitle(), header, msg);
|
||||
}
|
||||
}
|
||||
} catch (Exception e1) {
|
||||
LOG.error("Couldn't show notification", e1);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 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);
|
||||
// }
|
||||
// });
|
||||
|
||||
|
||||
for (EventHandlerConfiguration config : Config.getInstance().getSettings().eventHandlers) {
|
||||
EventHandler handler = new EventHandler(config);
|
||||
EventBusHolder.register(handler);
|
||||
LOG.debug("Registered event handler for {} {}", config.getEvent(), config.getName());
|
||||
}
|
||||
LOG.debug("Alert System registered");
|
||||
}
|
||||
|
||||
|
|
|
@ -207,4 +207,9 @@ public class JavaFxModel implements Model {
|
|||
public void setDisplayName(String name) {
|
||||
delegate.setDisplayName(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Model o) {
|
||||
return delegate.compareTo(o);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package ctbrec.ui.controls;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
|
@ -11,6 +14,7 @@ import javafx.stage.Stage;
|
|||
|
||||
public class Wizard extends BorderPane {
|
||||
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(Wizard.class);
|
||||
private Pane[] pages;
|
||||
private StackPane stack;
|
||||
private Stage stage;
|
||||
|
@ -18,6 +22,7 @@ public class Wizard extends BorderPane {
|
|||
private Button next;
|
||||
private Button prev;
|
||||
private Button finish;
|
||||
private boolean cancelled = true;
|
||||
|
||||
public Wizard(Stage stage, Pane... pages) {
|
||||
this.stage = stage;
|
||||
|
@ -33,42 +38,55 @@ public class Wizard extends BorderPane {
|
|||
private void createUi() {
|
||||
stack = new StackPane();
|
||||
setCenter(stack);
|
||||
|
||||
|
||||
next = new Button("Next");
|
||||
next.setOnAction(evt -> nextPage());
|
||||
prev = new Button("Prev");
|
||||
prev = new Button("Back");
|
||||
prev.setOnAction(evt -> prevPage());
|
||||
prev.visibleProperty().bind(next.visibleProperty());
|
||||
next.setVisible(pages.length > 1);
|
||||
Button cancel = new Button("Cancel");
|
||||
cancel.setOnAction(evt -> stage.close());
|
||||
finish = new Button("Finish");
|
||||
finish.setOnAction(evt -> {
|
||||
cancelled = false;
|
||||
stage.close();
|
||||
});
|
||||
HBox buttons = new HBox(5, prev, next, cancel, finish);
|
||||
buttons.setAlignment(Pos.BASELINE_RIGHT);
|
||||
setBottom(buttons);
|
||||
BorderPane.setMargin(buttons, new Insets(5));
|
||||
BorderPane.setMargin(buttons, new Insets(10));
|
||||
|
||||
if (pages.length != 0) {
|
||||
stack.getChildren().add(pages[0]);
|
||||
prevPage();
|
||||
}
|
||||
setButtonStates();
|
||||
}
|
||||
|
||||
private void prevPage() {
|
||||
page = Math.max(0, --page);
|
||||
stack.getChildren().clear();
|
||||
stack.getChildren().add(pages[page]);
|
||||
setButtonStates();
|
||||
updateState();
|
||||
}
|
||||
|
||||
private void nextPage() {
|
||||
page = Math.min(pages.length - 1, ++page);
|
||||
stack.getChildren().clear();
|
||||
stack.getChildren().add(pages[page]);
|
||||
setButtonStates();
|
||||
updateState();
|
||||
}
|
||||
|
||||
private void setButtonStates() {
|
||||
private void updateState() {
|
||||
prev.setDisable(page == 0);
|
||||
next.setDisable(page == pages.length - 1);
|
||||
finish.setDisable(page != pages.length - 1);
|
||||
LOG.debug("Setting border");
|
||||
pages[page].setStyle(
|
||||
"-fx-background-color: -fx-inner-border, -fx-background;"+
|
||||
"-fx-background-insets: 0 0 -1 0, 0, 1, 2;");
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -1,15 +1,19 @@
|
|||
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;
|
||||
|
||||
public class PlaySound extends Action {
|
||||
|
||||
private URL url;
|
||||
|
||||
public PlaySound() {}
|
||||
|
||||
public PlaySound(URL url) {
|
||||
this.url = url;
|
||||
name = "play sound";
|
||||
|
@ -20,4 +24,10 @@ public class PlaySound extends Action {
|
|||
AudioClip clip = new AudioClip(url.toString());
|
||||
clip.play();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ActionConfiguration config) throws Exception {
|
||||
File file = new File((String) config.getConfiguration().get("file"));
|
||||
url = file.toURI().toURL();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package ctbrec.ui.event;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.OS;
|
||||
import ctbrec.event.Action;
|
||||
import ctbrec.event.Event;
|
||||
import ctbrec.event.EventHandlerConfiguration.ActionConfiguration;
|
||||
import ctbrec.event.ModelStateChangedEvent;
|
||||
import ctbrec.event.RecordingStateChangedEvent;
|
||||
import ctbrec.ui.CamrecApplication;
|
||||
|
||||
public class ShowNotification extends Action {
|
||||
|
||||
public ShowNotification() {
|
||||
name = "show notification";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Event evt) {
|
||||
String header = evt.getType().toString();
|
||||
String msg;
|
||||
switch(evt.getType()) {
|
||||
case MODEL_STATUS_CHANGED:
|
||||
ModelStateChangedEvent modelEvent = (ModelStateChangedEvent) evt;
|
||||
Model m = modelEvent.getModel();
|
||||
msg = m.getDisplayName() + " is now " + modelEvent.getNewState().toString();
|
||||
break;
|
||||
case RECORDING_STATUS_CHANGED:
|
||||
RecordingStateChangedEvent recEvent = (RecordingStateChangedEvent) evt;
|
||||
m = recEvent.getModel();
|
||||
msg = "Recording for model " + m.getDisplayName() + " is now in state " + recEvent.getState().toString();
|
||||
break;
|
||||
default:
|
||||
msg = evt.getDescription();
|
||||
}
|
||||
OS.notification(CamrecApplication.title, header, msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ActionConfiguration config) throws Exception {
|
||||
}
|
||||
}
|
|
@ -1,35 +1,95 @@
|
|||
package ctbrec.ui.settings;
|
||||
|
||||
import java.io.File;
|
||||
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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.Config;
|
||||
import ctbrec.Model;
|
||||
import ctbrec.OS;
|
||||
import ctbrec.Recording;
|
||||
import ctbrec.event.Event;
|
||||
import ctbrec.event.EventBusHolder;
|
||||
import ctbrec.event.EventHandler;
|
||||
import ctbrec.event.EventHandlerConfiguration;
|
||||
import ctbrec.event.EventHandlerConfiguration.ActionConfiguration;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
import ctbrec.event.ExecuteProgram;
|
||||
import ctbrec.event.ModelPredicate;
|
||||
import ctbrec.event.ModelStatePredicate;
|
||||
import ctbrec.event.RecordingStatePredicate;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.ui.CamrecApplication;
|
||||
import ctbrec.ui.controls.FileSelectionBox;
|
||||
import ctbrec.ui.controls.ProgramSelectionBox;
|
||||
import ctbrec.ui.controls.Wizard;
|
||||
import ctbrec.ui.event.PlaySound;
|
||||
import ctbrec.ui.event.ShowNotification;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Orientation;
|
||||
import javafx.geometry.VPos;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ComboBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.ScrollPane;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.SelectionMode;
|
||||
import javafx.scene.control.Separator;
|
||||
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.scene.layout.Priority;
|
||||
import javafx.stage.Modality;
|
||||
import javafx.stage.Stage;
|
||||
import javafx.stage.Window;
|
||||
|
||||
public class ActionSettingsPanel extends TitledPane {
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(ActionSettingsPanel.class);
|
||||
private ListView<EventHandlerConfiguration> actionTable;
|
||||
|
||||
private TableView actionTable;
|
||||
private TextField name = new TextField();
|
||||
private ComboBox<Event.Type> event = new ComboBox<>();
|
||||
private ComboBox<Model.State> modelState = new ComboBox<>();
|
||||
private ComboBox<Recording.State> recordingState = new ComboBox<>();
|
||||
|
||||
public ActionSettingsPanel(SettingsTab settingsTab) {
|
||||
private CheckBox playSound = new CheckBox("Play sound");
|
||||
private FileSelectionBox sound = new FileSelectionBox();
|
||||
private CheckBox showNotification = new CheckBox("Notify me");
|
||||
private Button testNotification = new Button("Test");
|
||||
private CheckBox executeProgram = new CheckBox("Execute program");
|
||||
private ProgramSelectionBox program = new ProgramSelectionBox();
|
||||
private ListSelectionPane<Model> modelSelectionPane;
|
||||
|
||||
private Recorder recorder;
|
||||
|
||||
public ActionSettingsPanel(SettingsTab settingsTab, Recorder recorder) {
|
||||
this.recorder = recorder;
|
||||
setText("Events & Actions");
|
||||
setExpanded(true);
|
||||
setCollapsible(false);
|
||||
createGui();
|
||||
loadEventHandlers();
|
||||
}
|
||||
|
||||
private void loadEventHandlers() {
|
||||
actionTable.getItems().addAll(Config.getInstance().getSettings().eventHandlers);
|
||||
}
|
||||
|
||||
private void createGui() {
|
||||
|
@ -37,58 +97,202 @@ public class ActionSettingsPanel extends TitledPane {
|
|||
setContent(mainLayout);
|
||||
|
||||
actionTable = createActionTable();
|
||||
actionTable.setPrefSize(300, 200);
|
||||
ScrollPane scrollPane = new ScrollPane(actionTable);
|
||||
scrollPane.setFitToHeight(true);
|
||||
scrollPane.setFitToWidth(true);
|
||||
scrollPane.setBorder(Border.EMPTY);
|
||||
scrollPane.setStyle("-fx-background-color: -fx-background");
|
||||
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);
|
||||
HBox buttons = new HBox(5, add, delete);
|
||||
mainLayout.setBottom(buttons);
|
||||
BorderPane.setMargin(buttons, new Insets(5));
|
||||
BorderPane.setMargin(buttons, new Insets(5, 0, 0, 0));
|
||||
|
||||
actionTable.getSelectionModel().getSelectedItems().addListener(new ListChangeListener<EventHandlerConfiguration>() {
|
||||
@Override
|
||||
public void onChanged(Change<? extends EventHandlerConfiguration> change) {
|
||||
delete.setDisable(change.getList().isEmpty());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
Pane actionPane = createActionPane();
|
||||
Stage dialog = new Stage();
|
||||
dialog.initModality(Modality.APPLICATION_MODAL);
|
||||
dialog.initOwner(getScene().getWindow());
|
||||
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);
|
||||
Wizard root = new Wizard(dialog, actionPane);
|
||||
Scene scene = new Scene(root, 800, 540);
|
||||
scene.getStylesheets().addAll(getScene().getStylesheets());
|
||||
dialog.setScene(scene);
|
||||
centerOnParent(dialog);
|
||||
dialog.showAndWait();
|
||||
if(!root.isCancelled()) {
|
||||
createEventHandler();
|
||||
}
|
||||
}
|
||||
|
||||
private void createEventHandler() {
|
||||
EventHandlerConfiguration config = new EventHandlerConfiguration();
|
||||
config.setName(name.getText());
|
||||
config.setEvent(event.getValue());
|
||||
if(event.getValue() == Event.Type.MODEL_STATUS_CHANGED) {
|
||||
PredicateConfiguration 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) {
|
||||
PredicateConfiguration 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);
|
||||
}
|
||||
if(!modelSelectionPane.isAllSelected()) {
|
||||
PredicateConfiguration 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()) {
|
||||
ActionConfiguration ac = new ActionConfiguration();
|
||||
ac.setType(ShowNotification.class.getName());
|
||||
ac.setName("show notification");
|
||||
config.getActions().add(ac);
|
||||
}
|
||||
if(playSound.isSelected()) {
|
||||
ActionConfiguration ac = new ActionConfiguration();
|
||||
ac.setType(PlaySound.class.getName());
|
||||
File file = sound.fileProperty().get();
|
||||
ac.getConfiguration().put("file", file.getAbsolutePath());
|
||||
ac.setName("play " + file.getName());
|
||||
config.getActions().add(ac);
|
||||
}
|
||||
if(executeProgram.isSelected()) {
|
||||
ActionConfiguration ac = new ActionConfiguration();
|
||||
ac.setType(ExecuteProgram.class.getName());
|
||||
File file = program.fileProperty().get();
|
||||
ac.getConfiguration().put("file", file.getAbsolutePath());
|
||||
ac.setName("execute " + file.getName());
|
||||
config.getActions().add(ac);
|
||||
}
|
||||
|
||||
EventHandler handler = new EventHandler(config);
|
||||
EventBusHolder.register(handler);
|
||||
Config.getInstance().getSettings().eventHandlers.add(config);
|
||||
actionTable.getItems().add(config);
|
||||
LOG.debug("Registered event handler for {} {}", config.getEvent(), config.getName());
|
||||
}
|
||||
|
||||
private void delete(ActionEvent evt) {
|
||||
|
||||
List<EventHandlerConfiguration> selected = new ArrayList<>(actionTable.getSelectionModel().getSelectedItems());
|
||||
for (EventHandlerConfiguration config : selected) {
|
||||
EventBusHolder.unregister(config.getId());
|
||||
Config.getInstance().getSettings().eventHandlers.remove(config);
|
||||
actionTable.getItems().remove(config);
|
||||
}
|
||||
}
|
||||
|
||||
private Pane createNamePane(EventHandlerConfiguration config) {
|
||||
private Pane createActionPane() {
|
||||
GridPane layout = SettingsTab.createGridLayout();
|
||||
recordingState.prefWidthProperty().bind(event.widthProperty());
|
||||
modelState.prefWidthProperty().bind(event.widthProperty());
|
||||
name.prefWidthProperty().bind(event.widthProperty());
|
||||
|
||||
int row = 0;
|
||||
layout.add(new Label("Name"), 0, row);
|
||||
TextField name = new TextField();
|
||||
layout.add(name, 1, row);
|
||||
layout.add(name, 1, row++);
|
||||
|
||||
layout.add(new Label("Event"), 0, row);
|
||||
event.getItems().add(Event.Type.MODEL_STATUS_CHANGED);
|
||||
event.getItems().add(Event.Type.RECORDING_STATUS_CHANGED);
|
||||
event.setOnAction(evt -> {
|
||||
modelState.setVisible(event.getSelectionModel().getSelectedItem() == Event.Type.MODEL_STATUS_CHANGED);
|
||||
});
|
||||
event.getSelectionModel().select(Event.Type.MODEL_STATUS_CHANGED);
|
||||
layout.add(event, 1, row++);
|
||||
|
||||
layout.add(new Label("State"), 0, row);
|
||||
modelState.getItems().addAll(Model.State.values());
|
||||
layout.add(modelState, 1, row);
|
||||
recordingState.getItems().addAll(Recording.State.values());
|
||||
layout.add(recordingState, 1, row++);
|
||||
recordingState.visibleProperty().bind(modelState.visibleProperty().not());
|
||||
|
||||
layout.add(createSeparator(), 0, row++);
|
||||
|
||||
Label l = new Label("Models");
|
||||
layout.add(l, 0, row);
|
||||
modelSelectionPane = new ListSelectionPane<Model>(recorder.getModelsRecording(), Collections.emptyList());
|
||||
layout.add(modelSelectionPane, 1, row++);
|
||||
GridPane.setValignment(l, VPos.TOP);
|
||||
GridPane.setHgrow(modelSelectionPane, Priority.ALWAYS);
|
||||
GridPane.setFillWidth(modelSelectionPane, true);
|
||||
|
||||
layout.add(createSeparator(), 0, row++);
|
||||
|
||||
layout.add(showNotification, 0, row);
|
||||
layout.add(testNotification, 1, row++);
|
||||
testNotification.setOnAction(evt -> {
|
||||
DateTimeFormatter format = DateTimeFormatter.ofLocalizedTime(FormatStyle.MEDIUM);
|
||||
ZonedDateTime time = ZonedDateTime.now();
|
||||
OS.notification(CamrecApplication.title, "Test Notification", "Oi, what's up! " + format.format(time));
|
||||
});
|
||||
testNotification.disableProperty().bind(showNotification.selectedProperty().not());
|
||||
|
||||
layout.add(playSound, 0, row);
|
||||
layout.add(sound, 1, row++);
|
||||
sound.disableProperty().bind(playSound.selectedProperty().not());
|
||||
|
||||
layout.add(executeProgram, 0, row);
|
||||
layout.add(program, 1, row);
|
||||
program.disableProperty().bind(executeProgram.selectedProperty().not());
|
||||
|
||||
GridPane.setFillWidth(name, true);
|
||||
GridPane.setHgrow(name, Priority.ALWAYS);
|
||||
GridPane.setFillWidth(sound, true);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
|
||||
private TableView createActionTable() {
|
||||
TableView view = new TableView();
|
||||
private ListView<EventHandlerConfiguration> createActionTable() {
|
||||
ListView<EventHandlerConfiguration> view = new ListView<>();
|
||||
view.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||
view.setPrefSize(300, 200);
|
||||
return view;
|
||||
}
|
||||
|
||||
private Node createSeparator() {
|
||||
Separator divider = new Separator(Orientation.HORIZONTAL);
|
||||
GridPane.setHgrow(divider, Priority.ALWAYS);
|
||||
GridPane.setFillWidth(divider, true);
|
||||
GridPane.setColumnSpan(divider, 2);
|
||||
int tb = 20;
|
||||
int lr = 0;
|
||||
GridPane.setMargin(divider, new Insets(tb, lr, tb, lr));
|
||||
return divider;
|
||||
}
|
||||
|
||||
private void centerOnParent(Stage dialog) {
|
||||
dialog.setWidth(dialog.getScene().getWidth());
|
||||
dialog.setHeight(dialog.getScene().getHeight());
|
||||
double w = dialog.getWidth();
|
||||
double h = dialog.getHeight();
|
||||
Window p = dialog.getOwner();
|
||||
double px = p.getX();
|
||||
double py = p.getY();
|
||||
double pw = p.getWidth();
|
||||
double ph = p.getHeight();
|
||||
dialog.setX(px + (pw - w) / 2);
|
||||
dialog.setY(py + (ph - h) / 2);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
package ctbrec.ui.settings;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.ListView;
|
||||
import javafx.scene.control.SelectionMode;
|
||||
import javafx.scene.layout.GridPane;
|
||||
import javafx.scene.layout.Priority;
|
||||
import javafx.scene.layout.VBox;
|
||||
|
||||
public class ListSelectionPane<T extends Comparable<T>> extends GridPane {
|
||||
|
||||
private ListView<T> availableListView = new ListView<>();
|
||||
private ListView<T> selectedListView = new ListView<>();
|
||||
private Button addModel = new Button(">");
|
||||
private Button removeModel = new Button("<");
|
||||
private CheckBox selectAll = new CheckBox("all");
|
||||
|
||||
public ListSelectionPane(List<T> available, List<T> selected) {
|
||||
super();
|
||||
setHgap(5);
|
||||
setVgap(5);
|
||||
|
||||
createGui();
|
||||
fillLists(available, selected);
|
||||
}
|
||||
|
||||
private void fillLists(List<T> available, List<T> selected) {
|
||||
ObservableList<T> obsAvail = FXCollections.observableArrayList(available);
|
||||
ObservableList<T> obsSel = FXCollections.observableArrayList(selected);
|
||||
for (Iterator<T> iterator = obsAvail.iterator(); iterator.hasNext();) {
|
||||
T t = iterator.next();
|
||||
if(obsSel.contains(t)) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
Collections.sort(obsAvail);
|
||||
Collections.sort(obsSel);
|
||||
availableListView.setItems(obsAvail);
|
||||
selectedListView.setItems(obsSel);
|
||||
availableListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||
selectedListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||||
}
|
||||
|
||||
private void createGui() {
|
||||
Label labelAvailable = new Label("Available");
|
||||
Label labelSelected = new Label("Selected");
|
||||
|
||||
add(labelAvailable, 0, 0);
|
||||
add(availableListView, 0, 1);
|
||||
|
||||
VBox buttonBox = new VBox(5);
|
||||
buttonBox.getChildren().add(addModel);
|
||||
buttonBox.getChildren().add(removeModel);
|
||||
buttonBox.setAlignment(Pos.CENTER);
|
||||
add(buttonBox, 1, 1);
|
||||
|
||||
add(labelSelected, 2, 0);
|
||||
add(selectedListView, 2, 1);
|
||||
|
||||
add(selectAll, 0, 2);
|
||||
|
||||
GridPane.setHgrow(availableListView, Priority.ALWAYS);
|
||||
GridPane.setHgrow(selectedListView, Priority.ALWAYS);
|
||||
GridPane.setFillWidth(availableListView, true);
|
||||
GridPane.setFillWidth(selectedListView, true);
|
||||
|
||||
addModel.setOnAction(evt -> addSelectedItems());
|
||||
removeModel.setOnAction(evt -> removeSelectedItems());
|
||||
|
||||
availableListView.disableProperty().bind(selectAll.selectedProperty());
|
||||
selectedListView.disableProperty().bind(selectAll.selectedProperty());
|
||||
addModel.disableProperty().bind(selectAll.selectedProperty());
|
||||
removeModel.disableProperty().bind(selectAll.selectedProperty());
|
||||
}
|
||||
|
||||
private void addSelectedItems() {
|
||||
List<T> selected = new ArrayList<>(availableListView.getSelectionModel().getSelectedItems());
|
||||
for (T t : selected) {
|
||||
if(!selectedListView.getItems().contains(t)) {
|
||||
selectedListView.getItems().add(t);
|
||||
availableListView.getItems().remove(t);
|
||||
}
|
||||
}
|
||||
Collections.sort(selectedListView.getItems());
|
||||
}
|
||||
|
||||
private void removeSelectedItems() {
|
||||
List<T> selected = new ArrayList<>(selectedListView.getSelectionModel().getSelectedItems());
|
||||
for (T t : selected) {
|
||||
if(!availableListView.getItems().contains(t)) {
|
||||
availableListView.getItems().add(t);
|
||||
selectedListView.getItems().remove(t);
|
||||
}
|
||||
}
|
||||
Collections.sort(availableListView.getItems());
|
||||
}
|
||||
|
||||
public List<T> getSelectedItems() {
|
||||
if(selectAll.isSelected()) {
|
||||
List<T> all = new ArrayList<>(availableListView.getItems());
|
||||
all.addAll(selectedListView.getItems());
|
||||
return all;
|
||||
} else {
|
||||
return selectedListView.getItems();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAllSelected() {
|
||||
return selectAll.isSelected();
|
||||
}
|
||||
}
|
|
@ -15,6 +15,7 @@ import ctbrec.Config;
|
|||
import ctbrec.Hmac;
|
||||
import ctbrec.Settings.DirectoryStructure;
|
||||
import ctbrec.StringUtil;
|
||||
import ctbrec.recorder.Recorder;
|
||||
import ctbrec.sites.ConfigUI;
|
||||
import ctbrec.sites.Site;
|
||||
import ctbrec.ui.SiteUiFactory;
|
||||
|
@ -73,9 +74,11 @@ public class SettingsTab extends Tab implements TabSelectionListener {
|
|||
private List<Site> sites;
|
||||
private Label restartLabel;
|
||||
private Accordion siteConfigAccordion = new Accordion();
|
||||
private Recorder recorder;
|
||||
|
||||
public SettingsTab(List<Site> sites) {
|
||||
public SettingsTab(List<Site> sites, Recorder recorder) {
|
||||
this.sites = sites;
|
||||
this.recorder = recorder;
|
||||
setText("Settings");
|
||||
createGui();
|
||||
setClosable(false);
|
||||
|
@ -125,7 +128,7 @@ public class SettingsTab extends Tab implements TabSelectionListener {
|
|||
|
||||
//right side
|
||||
rightSide.getChildren().add(siteConfigAccordion);
|
||||
ActionSettingsPanel actions = new ActionSettingsPanel(this);
|
||||
ActionSettingsPanel actions = new ActionSettingsPanel(this, recorder);
|
||||
rightSide.getChildren().add(actions);
|
||||
proxySettingsPane = new ProxySettingsPane(this);
|
||||
rightSide.getChildren().add(proxySettingsPane);
|
||||
|
|
|
@ -3,6 +3,7 @@ package ctbrec;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
import com.squareup.moshi.JsonReader;
|
||||
|
@ -162,6 +163,13 @@ public abstract class AbstractModel implements Model {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Model o) {
|
||||
String thisName = Optional.ofNullable(getDisplayName()).orElse("").toLowerCase();
|
||||
String otherName = Optional.ofNullable(o).map(m -> m.getDisplayName()).orElse("").toLowerCase();
|
||||
return thisName.compareTo(otherName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getName();
|
||||
|
|
|
@ -12,7 +12,7 @@ import com.squareup.moshi.JsonWriter;
|
|||
import ctbrec.recorder.download.StreamSource;
|
||||
import ctbrec.sites.Site;
|
||||
|
||||
public interface Model {
|
||||
public interface Model extends Comparable<Model> {
|
||||
|
||||
public static enum State {
|
||||
ONLINE("online"),
|
||||
|
|
|
@ -4,6 +4,8 @@ import java.io.File;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ctbrec.event.EventHandlerConfiguration;
|
||||
|
||||
public class Settings {
|
||||
|
||||
public enum ProxyType {
|
||||
|
@ -56,7 +58,8 @@ public class Settings {
|
|||
public String cam4Password;
|
||||
public String lastDownloadDir = "";
|
||||
|
||||
public List<Model> models = new ArrayList<Model>();
|
||||
public List<Model> models = new ArrayList<>();
|
||||
public List<EventHandlerConfiguration> eventHandlers = new ArrayList<>();
|
||||
public boolean determineResolution = false;
|
||||
public boolean requireAuthentication = false;
|
||||
public boolean chooseStreamQuality = false;
|
||||
|
|
|
@ -2,6 +2,8 @@ package ctbrec.event;
|
|||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import ctbrec.event.EventHandlerConfiguration.ActionConfiguration;
|
||||
|
||||
public abstract class Action implements Consumer<Event> {
|
||||
|
||||
protected String name;
|
||||
|
@ -13,4 +15,11 @@ public abstract class Action implements Consumer<Event> {
|
|||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public abstract void configure(ActionConfiguration config) throws Exception;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,16 +1,37 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.google.common.eventbus.AsyncEventBus;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
|
||||
public class EventBusHolder {
|
||||
|
||||
public static final String EVENT = "event";
|
||||
public static final String OLD = "old";
|
||||
public static final String STATUS = "status";
|
||||
public static final String MODEL = "model";
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(EventBusHolder.class);
|
||||
private static Map<String, EventHandler> handlers = new HashMap<>();
|
||||
|
||||
public static final EventBus BUS = new AsyncEventBus(Executors.newSingleThreadExecutor());
|
||||
|
||||
public static void register(EventHandler handler) {
|
||||
if(handlers.containsKey(handler.getId())) {
|
||||
LOG.warn("EventHandler with ID {} is already registered", handler.getId());
|
||||
} else {
|
||||
BUS.register(handler);
|
||||
handlers.put(handler.getId(), handler);
|
||||
LOG.debug("EventHandler with ID {} has been added", handler.getId());
|
||||
}
|
||||
}
|
||||
|
||||
public static void unregister(String id) {
|
||||
EventHandler handler = handlers.get(id);
|
||||
if(handler != null) {
|
||||
BUS.unregister(handler);
|
||||
handlers.remove(id);
|
||||
LOG.debug("EventHandler with ID {} has been removed", id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,35 +6,132 @@ import java.util.List;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class EventHandler {
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
private List<Predicate<Event>> predicates = new ArrayList<>();
|
||||
private List<Consumer<Event>> actions;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
|
||||
import ctbrec.event.Event.Type;
|
||||
import ctbrec.event.EventHandlerConfiguration.ActionConfiguration;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
|
||||
public class EventHandler {
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(EventHandler.class);
|
||||
|
||||
private List<EventPredicate> predicates = new ArrayList<>();
|
||||
private List<Action> actions;
|
||||
private Type event;
|
||||
private String id;
|
||||
|
||||
public EventHandler(EventHandlerConfiguration config) {
|
||||
id = config.getId();
|
||||
event = config.getEvent();
|
||||
actions = createActions(config);
|
||||
predicates = createPredicates(config);
|
||||
predicates.add(new EventTypePredicate(event));
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public EventHandler(Consumer<Event> action, Predicate<Event>... predicates) {
|
||||
public EventHandler(Action action, EventPredicate... predicates) {
|
||||
this(Collections.singletonList(action), predicates);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public EventHandler(List<Consumer<Event>> actions, Predicate<Event>... predicates) {
|
||||
public EventHandler(List<Action> actions, EventPredicate... predicates) {
|
||||
this.actions = actions;
|
||||
for (Predicate<Event> predicate : predicates) {
|
||||
for (EventPredicate predicate : predicates) {
|
||||
this.predicates.add(predicate);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void reactToEvent(Event evt) {
|
||||
boolean matches = true;
|
||||
for (Predicate<Event> predicate : predicates) {
|
||||
if(!predicate.test(evt)) {
|
||||
matches = false;
|
||||
try {
|
||||
boolean matches = true;
|
||||
for (Predicate<Event> predicate : predicates) {
|
||||
if(!predicate.test(evt)) {
|
||||
matches = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(matches) {
|
||||
for (Consumer<Event> action : actions) {
|
||||
action.accept(evt);
|
||||
if(matches) {
|
||||
for (Consumer<Event> action : actions) {
|
||||
action.accept(evt);
|
||||
}
|
||||
}
|
||||
} catch(Exception e) {
|
||||
LOG.error("Error while processing event", e);
|
||||
}
|
||||
}
|
||||
|
||||
private List<EventPredicate> createPredicates(EventHandlerConfiguration config) {
|
||||
List<EventPredicate> predicates = new ArrayList<>(config.getPredicates().size());
|
||||
for (PredicateConfiguration pc : config.getPredicates()) {
|
||||
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<EventPredicate> cls = (Class<EventPredicate>) Class.forName(pc.getType());
|
||||
if(cls == null) {
|
||||
LOG.warn("Ignoring unknown action {}", cls);
|
||||
continue;
|
||||
}
|
||||
EventPredicate predicate = cls.newInstance();
|
||||
predicate.configure(pc);
|
||||
predicates.add(predicate);
|
||||
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
|
||||
LOG.warn("Error while creating action {} {}", pc.getType(), pc.getConfiguration(), e);
|
||||
}
|
||||
}
|
||||
return predicates;
|
||||
}
|
||||
|
||||
private List<Action> createActions(EventHandlerConfiguration config) {
|
||||
List<Action> actions = new ArrayList<>(config.getActions().size());
|
||||
for (ActionConfiguration ac : config.getActions()) {
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<Action> cls = (Class<Action>) Class.forName(ac.getType());
|
||||
if(cls == null) {
|
||||
LOG.warn("Ignoring unknown action {}", cls);
|
||||
continue;
|
||||
}
|
||||
Action action = cls.newInstance();
|
||||
action.configure(ac);
|
||||
actions.add(action);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Error while creating action {} {}", ac.getType(), ac.getConfiguration(), e);
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
EventHandler other = (EventHandler) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -4,14 +4,30 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import ctbrec.Model;
|
||||
|
||||
public class EventHandlerConfiguration {
|
||||
|
||||
private String id;
|
||||
private String name;
|
||||
private Event.Type event;
|
||||
private List<PredicateConfiguration> predicates = new ArrayList<>();
|
||||
private List<ActionConfiguration> actions = new ArrayList<>();
|
||||
|
||||
public EventHandlerConfiguration() {
|
||||
id = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Event.Type getEvent() {
|
||||
return event;
|
||||
}
|
||||
|
@ -44,10 +60,16 @@ public class EventHandlerConfiguration {
|
|||
this.actions = actions;
|
||||
}
|
||||
|
||||
public class PredicateConfiguration {
|
||||
public static class PredicateConfiguration {
|
||||
private String name;
|
||||
private String type;
|
||||
private List<Model> models;
|
||||
private Map<String, Object> configuration = new HashMap<>();
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
@ -64,9 +86,22 @@ public class EventHandlerConfiguration {
|
|||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public List<Model> getModels() {
|
||||
return models;
|
||||
}
|
||||
|
||||
public void setModels(List<Model> models) {
|
||||
this.models = models;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public class ActionConfiguration {
|
||||
public static class ActionConfiguration {
|
||||
private String name;
|
||||
private String type;
|
||||
private Map<String, Object> configuration = new HashMap<>();
|
||||
|
||||
|
@ -85,5 +120,44 @@ public class EventHandlerConfiguration {
|
|||
public void setConfiguration(Map<String, Object> configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + ", when:" + predicates + " do:" + actions + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
EventHandlerConfiguration other = (EventHandlerConfiguration) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null)
|
||||
return false;
|
||||
} else if (!id.equals(other.id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
|
||||
public abstract class EventPredicate implements Predicate<Event> {
|
||||
|
||||
public abstract void configure(PredicateConfiguration pc);
|
||||
}
|
|
@ -1,14 +1,16 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import ctbrec.event.Event.Type;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
|
||||
public class EventTypePredicate implements Predicate<Event> {
|
||||
public class EventTypePredicate extends EventPredicate {
|
||||
|
||||
private Type type;
|
||||
|
||||
private EventTypePredicate(Type type) {
|
||||
public EventTypePredicate() {
|
||||
}
|
||||
|
||||
public EventTypePredicate(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
|
@ -17,7 +19,8 @@ public class EventTypePredicate implements Predicate<Event> {
|
|||
return evt.getType() == type;
|
||||
}
|
||||
|
||||
public static EventTypePredicate of(Type type) {
|
||||
return new EventTypePredicate(type);
|
||||
@Override
|
||||
public void configure(PredicateConfiguration pc) {
|
||||
type = Type.valueOf((String) pc.getConfiguration().get("type"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ctbrec.OS;
|
||||
import ctbrec.event.EventHandlerConfiguration.ActionConfiguration;
|
||||
import ctbrec.io.StreamRedirectThread;
|
||||
|
||||
public class ExecuteProgram extends Action {
|
||||
|
||||
private static final transient Logger LOG = LoggerFactory.getLogger(ExecuteProgram.class);
|
||||
|
||||
private String executable;
|
||||
|
||||
public ExecuteProgram() {}
|
||||
|
||||
public ExecuteProgram(String executable) {
|
||||
this.executable = executable;
|
||||
name = "execute program";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Event evt) {
|
||||
Runtime rt = Runtime.getRuntime();
|
||||
Process process = null;
|
||||
try {
|
||||
String[] args = {executable}; // TODO fill args array
|
||||
process = rt.exec(args, OS.getEnvironment());
|
||||
|
||||
// create threads, which read stdout and stderr of the player process. these are needed,
|
||||
// because otherwise the internal buffer for these streams fill up and block the process
|
||||
Thread std = new Thread(new StreamRedirectThread(process.getInputStream(), System.out));
|
||||
std.setName("Player stdout pipe");
|
||||
std.setDaemon(true);
|
||||
std.start();
|
||||
Thread err = new Thread(new StreamRedirectThread(process.getErrorStream(), System.err));
|
||||
err.setName("Player stderr pipe");
|
||||
err.setDaemon(true);
|
||||
err.start();
|
||||
|
||||
process.waitFor();
|
||||
LOG.debug("{} finished", name);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while processing {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(ActionConfiguration config) {
|
||||
executable = (String) config.getConfiguration().get("file");
|
||||
}
|
||||
}
|
|
@ -1,30 +1,57 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
|
||||
public class ModelPredicate implements Predicate<Event> {
|
||||
public class ModelPredicate extends EventPredicate {
|
||||
|
||||
private Model model;
|
||||
private Predicate<Event> internal;
|
||||
|
||||
private ModelPredicate(Model model) {
|
||||
this.model = model;
|
||||
public ModelPredicate() {}
|
||||
|
||||
public ModelPredicate(Model model) {
|
||||
internal = createFor(model);
|
||||
}
|
||||
|
||||
public ModelPredicate(List<Model> models) {
|
||||
configure(models);
|
||||
}
|
||||
|
||||
private void configure(List<Model> models) {
|
||||
if(models.isEmpty()) {
|
||||
throw new IllegalArgumentException("List has to contain at least one model");
|
||||
}
|
||||
|
||||
Predicate<Event> predicate = createFor(models.get(0));
|
||||
for (int i = 1; i < models.size(); i++) {
|
||||
predicate = predicate.or(createFor(models.get(i)));
|
||||
}
|
||||
internal = predicate;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
return internal.test(evt);
|
||||
}
|
||||
|
||||
public static ModelPredicate of(Model model) {
|
||||
return new ModelPredicate(model);
|
||||
private Predicate<Event> createFor(Model model) {
|
||||
return evt -> {
|
||||
if(evt instanceof AbstractModelEvent) {
|
||||
AbstractModelEvent modelEvent = (AbstractModelEvent) evt;
|
||||
Model other = modelEvent.getModel();
|
||||
return Objects.equals(model, other);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(PredicateConfiguration pc) {
|
||||
configure(pc.getModels());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,22 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import ctbrec.Model;
|
||||
import ctbrec.Model.State;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
|
||||
public class ModelStatePredicate implements Predicate<Event> {
|
||||
public class ModelStatePredicate extends EventPredicate {
|
||||
|
||||
private Model.State state;
|
||||
|
||||
private ModelStatePredicate(Model.State state) {
|
||||
public ModelStatePredicate() {}
|
||||
|
||||
public ModelStatePredicate(Model.State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Event evt) {
|
||||
if(evt instanceof AbstractModelEvent) {
|
||||
if(evt instanceof ModelStateChangedEvent) {
|
||||
ModelStateChangedEvent modelEvent = (ModelStateChangedEvent) evt;
|
||||
Model.State newState = modelEvent.getNewState();
|
||||
return newState == state;
|
||||
|
@ -23,7 +25,8 @@ public class ModelStatePredicate implements Predicate<Event> {
|
|||
}
|
||||
}
|
||||
|
||||
public static ModelStatePredicate of(Model.State state) {
|
||||
return new ModelStatePredicate(state);
|
||||
@Override
|
||||
public void configure(PredicateConfiguration pc) {
|
||||
state = State.valueOf((String) pc.getConfiguration().get("state"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,10 @@ public class RecordingStateChangedEvent extends AbstractModelEvent {
|
|||
};
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return newState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RecordingStateChanged[" + newState + "," + model.getDisplayName() + "," + path + "]";
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
package ctbrec.event;
|
||||
|
||||
import ctbrec.Recording;
|
||||
import ctbrec.event.EventHandlerConfiguration.PredicateConfiguration;
|
||||
|
||||
public class RecordingStatePredicate extends EventPredicate {
|
||||
|
||||
private Recording.State state;
|
||||
|
||||
public RecordingStatePredicate() {}
|
||||
|
||||
public RecordingStatePredicate(Recording.State state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean test(Event evt) {
|
||||
if(evt instanceof RecordingStateChangedEvent) {
|
||||
RecordingStateChangedEvent event = (RecordingStateChangedEvent) evt;
|
||||
Recording.State newState = event.getState();
|
||||
return newState == state;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(PredicateConfiguration pc) {
|
||||
state = Recording.State.valueOf((String) pc.getConfiguration().get("state"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue