![JAR search and dependency download from the Maven repository](/logo.png)
org.jhotdraw8.application.action.file.AbstractSaveFileAction Maven / Gradle / Ivy
/*
* @(#)AbstractSaveFileAction.java
* Copyright © 2023 The authors and contributors of JHotDraw. MIT License.
*/
package org.jhotdraw8.application.action.file;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Dialog;
import javafx.scene.input.DataFormat;
import javafx.stage.Modality;
import org.jhotdraw8.annotation.NonNull;
import org.jhotdraw8.annotation.Nullable;
import org.jhotdraw8.application.ApplicationLabels;
import org.jhotdraw8.application.FileBasedActivity;
import org.jhotdraw8.application.action.AbstractActivityAction;
import org.jhotdraw8.application.controls.urichooser.FileURIChooser;
import org.jhotdraw8.application.controls.urichooser.URIChooser;
import org.jhotdraw8.application.resources.Resources;
import org.jhotdraw8.base.net.UriUtil;
import org.jhotdraw8.fxbase.concurrent.SimpleWorkState;
import org.jhotdraw8.fxbase.concurrent.WorkState;
import org.jhotdraw8.fxcollection.typesafekey.Key;
import org.jhotdraw8.fxcollection.typesafekey.NullableObjectKey;
import org.jhotdraw8.fxcollection.typesafekey.SimpleParameterizedType;
import org.jhotdraw8.icollection.ChampMap;
import java.net.URI;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;
import java.util.SequencedMap;
import java.util.concurrent.CancellationException;
import java.util.function.Supplier;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Saves the changes in the active view. If the active view has not an URI, an
* {@code URIChooser} is presented.
*
* @author Werner Randelshofer
*/
public abstract class AbstractSaveFileAction extends AbstractActivityAction {
private final boolean saveAs;
private Node oldFocusOwner;
public static final @NonNull Key SAVE_CHOOSER_KEY = new NullableObjectKey<>("saveChooser", URIChooser.class);
public static final @NonNull Key> SAVE_CHOOSER_FACTORY_KEY = new NullableObjectKey<>("saveChooserFactory",
new SimpleParameterizedType(Supplier.class, URIChooser.class));
/**
* Creates a new instance.
*
* @param activity the view
* @param id the id
* @param saveAs whether to force a file dialog
*/
public AbstractSaveFileAction(@NonNull FileBasedActivity activity, String id, boolean saveAs) {
this(activity, id, saveAs, activity.getApplication().getResources());
}
/**
* Creates a new instance.
*
* @param activity the view
* @param id the id
* @param saveAs whether to force a file dialog
* @param resources the resources are used for setting labels and icons for the action
*/
public AbstractSaveFileAction(@NonNull FileBasedActivity activity, @NonNull String id, boolean saveAs, @NonNull Resources resources) {
super(activity);
this.saveAs = saveAs;
resources.configureAction(this, id);
}
protected @NonNull URIChooser getChooser(FileBasedActivity view) {
URIChooser chooser = app.get(SAVE_CHOOSER_KEY);
if (chooser == null) {
Supplier factory = app.get(SAVE_CHOOSER_FACTORY_KEY);
chooser = factory == null ? new FileURIChooser(FileURIChooser.Mode.SAVE) : factory.get();
app.set(SAVE_CHOOSER_KEY, chooser);
}
return chooser;
}
@Override
protected void onActionPerformed(@NonNull ActionEvent evt, @NonNull FileBasedActivity activity) {
oldFocusOwner = activity.getNode().getScene().getFocusOwner();
WorkState workState = new SimpleWorkState<>(getLabel());
activity.addDisabler(workState);
saveFileChooseUri(activity, workState);
}
protected void saveFileChooseUri(final @NonNull FileBasedActivity v, WorkState workState) {
if (v.getURI() == null || saveAs) {
URIChooser chsr = getChooser(v);
URI uri = chsr.showDialog(v.getNode());
if (uri != null) {
saveFileChooseOptions(v, uri, chsr.getDataFormat(), workState);
} else {
v.removeDisabler(workState);
}
if (oldFocusOwner != null) {
oldFocusOwner.requestFocus();
}
} else {
saveFileChooseOptions(v, v.getURI(), v.getDataFormat(), workState);
}
}
protected void saveFileChooseOptions(final @NonNull FileBasedActivity v, @NonNull URI uri, DataFormat format, WorkState workState) {
SequencedMap, Object> options = new LinkedHashMap<>();
Dialog, Object>> dialog = null;
try {
dialog = createOptionsDialog(format);
} catch (RuntimeException e) {
Alert alert = new Alert(Alert.AlertType.ERROR, createErrorMessage(e));
alert.getDialogPane().setMaxWidth(640.0);
Resources labels = ApplicationLabels.getResources();
alert.setHeaderText(labels.getFormatted("file.save.couldntSave.message", UriUtil.getName(uri)));
alert.showAndWait();
v.removeDisabler(this);
return;
}
if (dialog != null) {
dialog.initModality(Modality.WINDOW_MODAL);
dialog.initOwner(v.getNode().getScene().getWindow());
Optional, Object>> result = dialog.showAndWait();
if (result.isPresent()) {
options = result.get();
} else {
v.removeDisabler(workState);
return;
}
}
saveFileToUri(v, uri, format, options, workState);
}
protected void saveFileToUri(final @NonNull FileBasedActivity view, final @NonNull URI uri, final DataFormat format, @NonNull Map, Object> options, WorkState workState) {
view.write(uri, format, ChampMap.copyOf(options), workState).handle((result, exception) -> {
if (exception instanceof CancellationException) {
view.removeDisabler(workState);
if (oldFocusOwner != null) {
oldFocusOwner.requestFocus();
}
} else if (exception != null) {
Throwable value = exception;
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Unexpected Exception " + value.getMessage(), value);
Resources labels = ApplicationLabels.getResources();
Alert alert = new Alert(Alert.AlertType.ERROR, createErrorMessage(exception));
alert.getDialogPane().setMaxWidth(640.0);
alert.setHeaderText(labels.getFormatted("file.save.couldntSave.message", UriUtil.getName(uri)));
alert.showAndWait();
view.removeDisabler(workState);
if (oldFocusOwner != null) {
oldFocusOwner.requestFocus();
}
} else {
onSaveSucceeded(view, uri, format);
view.removeDisabler(workState);
if (oldFocusOwner != null) {
oldFocusOwner.requestFocus();
}
}
//noinspection ReturnOfNull
return null;
});
}
protected @Nullable Dialog, Object>> createOptionsDialog(DataFormat format) {
return null;
}
protected abstract void onSaveSucceeded(FileBasedActivity v, URI uri, DataFormat format);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy