Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* An event that occurs when a new connection is added to the pipeline. This is triggered by the
* user adding a connection with the GUI.
*/
public class ConnectionAddedEvent implements RunPipelineEvent {
public class ConnectionAddedEvent implements RunPipelineEvent, DirtiesSaveEvent {
private final Connection connection;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* An event that occurs when a connection is removed from the pipeline. This is triggered by the
* user deleting a connection with the GUI.
*/
public class ConnectionRemovedEvent {
public class ConnectionRemovedEvent implements DirtiesSaveEvent {
private final Connection connection;

/**
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/java/edu/wpi/grip/core/events/DirtiesSaveEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package edu.wpi.grip.core.events;

/**
* An event that can potentially dirty the save file.
*
* <p>These events ensure that anything that changes causes the save file to be flagged as dirty and
* in need of being saved for the project to be deemed "clean" again.
*/
public interface DirtiesSaveEvent {

/**
* Some events may have more logic regarding whether they make the save dirty or not.
*
* @return True if this event should dirty the project save
*/
default boolean doesDirtySave() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* An event that occurs when the value stored in a socket changes. This can happen, for example, as
* the result of an operation completing, or as a response to user input.
*/
public class SocketChangedEvent implements RunPipelineEvent {
public class SocketChangedEvent implements RunPipelineEvent, DirtiesSaveEvent {
private final Socket socket;

/**
Expand All @@ -31,6 +31,18 @@ public boolean isRegarding(Socket socket) {
return socket.equals(this.socket);
}

/**
* This event will only dirty the save if the InputSocket does not have connections.
* Thus the value can only have been changed by a UI component.
* If the socket has connections then the value change is triggered by another socket's change.
*
* @return True if this should dirty the save.
*/
@Override
public boolean doesDirtySave() {
return socket.getDirection() == Socket.Direction.INPUT && socket.getConnections().isEmpty();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same code as the method below it.
Can you refactor it into one method that is called by both methods?

Or just have one of these methods call the other one.


@Override
public boolean pipelineShouldRun() {
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* An event that occurs when a {@link OutputSocket} is set to be either previewed or not previewed.
* The GUI listens for these events so it knows which sockets to show previews for.
*/
public class SocketPreviewChangedEvent {
public class SocketPreviewChangedEvent implements DirtiesSaveEvent {
private final OutputSocket socket;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* @see Source
*/
public class SourceAddedEvent {
public class SourceAddedEvent implements DirtiesSaveEvent {
private final Source source;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* @see Source
*/
public class SourceRemovedEvent {
public class SourceRemovedEvent implements DirtiesSaveEvent {
private final Source source;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
* An event that occurs when a new step is added to the pipeline. This is triggered by the user
* adding a step with the GUI.
*/
public class StepAddedEvent {
public class StepAddedEvent implements DirtiesSaveEvent {
private final Step step;
private final OptionalInt index;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
/**
* An event that occurs when a new step is moved from one position to another in the pipeline.
*/
public class StepMovedEvent {
public class StepMovedEvent implements DirtiesSaveEvent {
private final Step step;
private final int distance;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* An event that occurs when a new step is removed from the pipeline. This is triggered by the user
* deleting a step from the GUI.
*/
public class StepRemovedEvent {
public class StepRemovedEvent implements DirtiesSaveEvent {
private final Step step;

/**
Expand Down
29 changes: 28 additions & 1 deletion core/src/main/java/edu/wpi/grip/core/serialization/Project.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

import edu.wpi.grip.core.Pipeline;
import edu.wpi.grip.core.PipelineRunner;
import edu.wpi.grip.core.events.DirtiesSaveEvent;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.eventbus.Subscribe;
import com.google.common.reflect.ClassPath;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
Expand All @@ -20,7 +22,8 @@
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.util.Optional;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaFX shouldn't be available in the core because it's not on the RoboRio. I don't know why this even compiles.

Can you check the build.gradle to see why you can even import javafx from within the core.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JavaFX is bundled in the desktop JRE, so it compiles fine. Project Jigsaw solves this, but it's getting released in March...

import javax.inject.Inject;
import javax.inject.Singleton;

Expand All @@ -36,6 +39,7 @@ public class Project {
@Inject
private PipelineRunner pipelineRunner;
private Optional<File> file = Optional.empty();
private final SimpleBooleanProperty saveIsDirty = new SimpleBooleanProperty(false);

@Inject
public void initialize(StepConverter stepConverter,
Expand Down Expand Up @@ -109,6 +113,7 @@ void open(Reader reader) {
this.pipeline.clear();
this.xstream.fromXML(reader);
pipelineRunner.startAsync();
saveIsDirty.set(false);
}

/**
Expand All @@ -124,5 +129,27 @@ public void save(File file) throws IOException {

public void save(Writer writer) {
this.xstream.toXML(this.pipeline, writer);
saveIsDirty.set(false);
}

public boolean isSaveDirty() {
return saveIsDirty.get();
}

public void addDirtyListener(ChangeListener<Boolean> changeListener) {
saveIsDirty.addListener(changeListener);
}

public void removeDirtyListener(ChangeListener<Boolean> changeListener) {
saveIsDirty.removeListener(changeListener);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this pattern but we can't do this using javafx


@Subscribe
public void onDirtiesSaveEvent(DirtiesSaveEvent dirtySaveEvent) {
// Only update the flag the save isn't already dirty
// We don't need to be redundantly checking if the event dirties the save
if (!saveIsDirty.get() && dirtySaveEvent.doesDirtySave()) {
saveIsDirty.set(true);
}
}
}
11 changes: 10 additions & 1 deletion ui/src/main/java/edu/wpi/grip/ui/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class Main extends Application {

private final Object dialogLock = new Object();
private static final Logger logger = Logger.getLogger(Main.class.getName());
private static final String MAIN_TITLE = "GRIP Computer Vision Engine";

/**
* JavaFX insists on creating the main application with its own reflection code, so we can't
Expand Down Expand Up @@ -123,9 +124,17 @@ public void start(Stage stage) throws IOException {
cvOperations.addOperations();
notifyPreloader(new Preloader.ProgressNotification(0.9));

project.addDirtyListener((observable, oldValue, newValue) -> {
if (newValue) {
stage.setTitle(MAIN_TITLE + " | Edited");
} else {
stage.setTitle(MAIN_TITLE);
}
});

// If this isn't here this can cause a deadlock on windows. See issue #297
stage.setOnCloseRequest(event -> SafeShutdown.exit(0, Platform::exit));
stage.setTitle("GRIP Computer Vision Engine");
stage.setTitle(MAIN_TITLE);
stage.getIcons().add(new Image("/edu/wpi/grip/ui/icons/grip.png"));
stage.setScene(new Scene(root));
notifyPreloader(new Preloader.ProgressNotification(1.0));
Expand Down
3 changes: 1 addition & 2 deletions ui/src/main/java/edu/wpi/grip/ui/MainWindowController.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ protected void initialize() {
.toString());
statusBar.setText(" Pipeline " + stateMessage);
}), Platform::runLater);

}

/**
Expand All @@ -103,7 +102,7 @@ protected void initialize() {
* @return true If the user has not chosen to
*/
private boolean showConfirmationDialogAndWait() {
if (!pipeline.getSteps().isEmpty()) {
if (!pipeline.getSteps().isEmpty() && project.isSaveDirty()) {
final ButtonType save = new ButtonType("Save");
final ButtonType dontSave = ButtonType.NO;
final ButtonType cancel = ButtonType.CANCEL;
Expand Down