Skip to content

Commit

Permalink
Ask to save the current layout when closing shuffleboard (#307)
Browse files Browse the repository at this point in the history
* Ask to save the current layout when closing shuffleboard

Fixes #173

* Set title, improve message text

* Add option to not show exit confirmation dialog

* Show confirmation dialog on File -> Close

Changes the MainWindowController.close() method to attempt to close the window rather than terminating the program
  • Loading branch information
SamCarlberg authored and bradamiller committed Nov 22, 2017
1 parent f669518 commit c564f64
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,11 @@
/* Bring the content to all edges */
-fx-padding: 0; /* 10 0 0 10 */
}

.dialog-pane .header-panel {
-fx-background-color: -swatch-500;
}

.dialog-pane .header-panel .label {
-fx-text-fill: white;
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
package edu.wpi.first.shuffleboard.app;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;

import edu.wpi.first.shuffleboard.api.DashboardMode;
import edu.wpi.first.shuffleboard.api.components.SourceTreeTable;
import edu.wpi.first.shuffleboard.api.components.WidgetPropertySheet;
import edu.wpi.first.shuffleboard.api.dnd.DataFormats;
import edu.wpi.first.shuffleboard.api.plugin.Plugin;
import edu.wpi.first.shuffleboard.api.prefs.FlushableProperty;
import edu.wpi.first.shuffleboard.api.sources.DataSource;
import edu.wpi.first.shuffleboard.api.sources.SourceEntry;
import edu.wpi.first.shuffleboard.api.sources.recording.Recorder;
Expand All @@ -19,13 +17,15 @@
import edu.wpi.first.shuffleboard.app.components.DashboardTab;
import edu.wpi.first.shuffleboard.app.components.DashboardTabPane;
import edu.wpi.first.shuffleboard.app.components.WidgetGallery;
import edu.wpi.first.shuffleboard.api.components.WidgetPropertySheet;
import edu.wpi.first.shuffleboard.app.json.JsonBuilder;
import edu.wpi.first.shuffleboard.app.plugin.PluginLoader;
import edu.wpi.first.shuffleboard.app.prefs.AppPreferences;
import edu.wpi.first.shuffleboard.api.prefs.FlushableProperty;
import edu.wpi.first.shuffleboard.app.sources.recording.Playback;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;

import org.fxmisc.easybind.EasyBind;

import java.io.File;
Expand Down Expand Up @@ -68,6 +68,8 @@
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import javafx.stage.WindowEvent;

import static edu.wpi.first.shuffleboard.api.components.SourceTreeTable.alphabetical;
import static edu.wpi.first.shuffleboard.api.components.SourceTreeTable.branchesFirst;
Expand Down Expand Up @@ -292,10 +294,17 @@ public void setDashboard(DashboardTabPane dashboard) {
centerSplitPane.getItems().add(dashboard);
}

/**
* Closes from interacting with the "Close" menu item.
*/
@FXML
public void close() {
log.info("Exiting app");
System.exit(0);

// Attempt to close the main window. This lets window closing handlers run. Calling System.exit() or Platform.exit()
// will more-or-less immediately terminate the application without calling these handlers.
Window window = root.getScene().getWindow();
window.fireEvent(new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
}

/**
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/edu/wpi/first/shuffleboard/app/Shuffleboard.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.Pane;
import javafx.stage.Screen;
import javafx.stage.Stage;
Expand Down Expand Up @@ -90,6 +92,30 @@ public void start(Stage primaryStage) throws IOException {
primaryStage.setMinHeight(480);
primaryStage.setWidth(Screen.getPrimary().getVisualBounds().getWidth());
primaryStage.setHeight(Screen.getPrimary().getVisualBounds().getHeight());
primaryStage.setOnCloseRequest(closeEvent -> {
if (!AppPreferences.getInstance().isConfirmExit()) {
// Don't show the confirmation dialog, just exit
return;
}
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Save layout");
alert.getDialogPane().getScene().getStylesheets().setAll(mainPane.getStylesheets());
alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
alert.getDialogPane().setHeaderText("Save the current layout before closing?");
alert.showAndWait().ifPresent(bt -> {
if (bt == ButtonType.YES) {
try {
mainWindowController.save();
} catch (IOException ex) {
logger.log(Level.WARNING, "Could not save the layout", ex);
}
} else if (bt == ButtonType.CANCEL) {
// cancel the close request by consuming the event
closeEvent.consume();
}
// Don't need to check for NO because it just lets the window close normally
});
});
primaryStage.show();
Time.setStartTime(Time.now());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
import javafx.beans.property.SimpleObjectProperty;

/**
* Contains the user preferences for the app. These preferences are user-specific and are saved
* to the users home directory and are not contained in save files.
* Contains the user preferences for the app. These preferences are user-specific and are not contained in save files.
*/
public final class AppPreferences {

Expand All @@ -28,6 +27,8 @@ public final class AppPreferences {
private final Property<File> saveFile = new SimpleObjectProperty<>(this, "saveFile", null);
private final BooleanProperty autoLoadLastSaveFile =
new SimpleBooleanProperty(this, "automaticallyLoadLastSaveFile", true);
private final BooleanProperty confirmExit =
new SimpleBooleanProperty(this, "showConfirmationDialogWhenExiting", true);

@VisibleForTesting
static AppPreferences instance = new AppPreferences();
Expand All @@ -41,11 +42,13 @@ public AppPreferences() {
PreferencesUtils.read(defaultTileSize, preferences);
PreferencesUtils.read(saveFile, preferences, File::new);
PreferencesUtils.read(autoLoadLastSaveFile, preferences);
PreferencesUtils.read(confirmExit, preferences);

theme.addListener(__ -> PreferencesUtils.save(theme, preferences, Theme::getName));
defaultTileSize.addListener(__ -> PreferencesUtils.save(defaultTileSize, preferences));
saveFile.addListener(__ -> PreferencesUtils.save(saveFile, preferences, File::getAbsolutePath));
autoLoadLastSaveFile.addListener(__ -> PreferencesUtils.save(autoLoadLastSaveFile, preferences));
confirmExit.addListener(__ -> PreferencesUtils.save(confirmExit, preferences));
}

public static AppPreferences getInstance() {
Expand All @@ -59,7 +62,8 @@ public ImmutableList<Property<?>> getProperties() {
return ImmutableList.of(
theme,
defaultTileSize,
autoLoadLastSaveFile
autoLoadLastSaveFile,
confirmExit
);
}

Expand Down Expand Up @@ -110,4 +114,16 @@ public BooleanProperty autoLoadLastSaveFileProperty() {
public void setAutoLoadLastSaveFile(boolean autoLoadLastSaveFile) {
this.autoLoadLastSaveFile.set(autoLoadLastSaveFile);
}

public boolean isConfirmExit() {
return confirmExit.get();
}

public BooleanProperty confirmExitProperty() {
return confirmExit;
}

public void setConfirmExit(boolean confirmExit) {
this.confirmExit.set(confirmExit);
}
}

0 comments on commit c564f64

Please sign in to comment.