/*
* This file is part of LaTeXDraw.
* Copyright (c) 2005-2017 Arnaud BLOUIN
* LaTeXDraw is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
* LaTeXDraw is distributed without any warranty; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package net.sf.latexdraw.instruments;
import com.google.inject.Inject;
import java.io.File;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.ResourceBundle;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuButton;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.stage.FileChooser;
import net.sf.latexdraw.LaTeXDraw;
import net.sf.latexdraw.actions.LoadDrawing;
import net.sf.latexdraw.actions.NewDrawing;
import net.sf.latexdraw.actions.SaveDrawing;
import net.sf.latexdraw.util.LNamespace;
import net.sf.latexdraw.util.LSystem;
import net.sf.latexdraw.util.LangTool;
import net.sf.latexdraw.view.svg.SVGDocumentGenerator;
import org.malai.action.Action;
import org.malai.javafx.action.IOAction;
import org.malai.javafx.binding.JfxMenuItemBinding;
import org.malai.javafx.instrument.JfxInstrument;
import org.malai.javafx.interaction.library.MenuItemPressed;
import org.malai.javafx.interaction.library.WindowClosed;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Saves and loads documents.
* @author Arnaud Blouin
*/
public class FileLoaderSaver extends JfxInstrument implements Initializable {
private static final BiFunction<IOAction<Label>, FileLoaderSaver, Void> initIOAction = (action, instrument) -> {
action.setStatusWidget(instrument.statusBar.getLabel());
action.setProgressBar(instrument.statusBar.getProgressBar());
action.setOpenSaveManager(SVGDocumentGenerator.INSTANCE);
action.setUi(LaTeXDraw.getINSTANCE());
return null;
};
/** The menu used to save documents. */
@FXML private MenuItem saveMenu;
/** The menu used to load documents. */
@FXML private MenuItem loadMenu;
/** The menu used to create a new document. */
@FXML private MenuItem newMenu;
/** The menu that contains the menu item corresponding to the recent documents. */
@FXML private Menu recentFilesMenu;
/** The menu item used to save as a document. */
@FXML private MenuItem saveAsMenu;
@FXML private MenuButton fileMenu;
/** The path where documents are saved. */
private String pathSave;
/** The current file loaded or saved. */
private File currentFile;
/** The current working folder. */
private File currentFolder;
/** The fileChooser used to save drawings. */
private FileChooser fileChooser;
private RecentMenuItem2LoadInteractor recentInterator;
/** The instrument used to manage preferences. */
@Inject private PreferencesSetter prefSetter;
@Inject private StatusBarController statusBar;
/**
* Creates the file loader/saver.
*/
FileLoaderSaver() {
super();
}
@Override
public void reinit() {
currentFile = null;
fileChooser = null;
}
@Override
public void onActionDone(final Action action) {
super.onActionDone(action);
// Updating the recent files on I/O actions.
if(action instanceof IOAction && action.hadEffect()) {
final IOAction<?> ioAction = (IOAction<?>) action;
currentFile = ioAction.getFile();
currentFolder = currentFile.getParentFile();
if(!currentFile.getPath().endsWith(".svg")) {//$NON-NLS-1$
currentFile = new File(currentFile.getPath() + ".svg");//$NON-NLS-1$
}
prefSetter.addRecentFile(((IOAction<?>) action).getFile().getPath());
updateRecentMenuItems(prefSetter.getRecentFileNames());
}
}
@Override
public void setActivated(final boolean activated, final boolean hide) {
super.setActivated(activated);
final boolean showButtons = activated || !hide;
newMenu.setVisible(showButtons);
saveAsMenu.setVisible(showButtons);
saveMenu.setVisible(showButtons);
loadMenu.setVisible(showButtons);
if(showButtons) {
newMenu.setDisable(!activated);
saveAsMenu.setDisable(!activated);
saveMenu.setDisable(!activated);
loadMenu.setDisable(!activated);
}
}
@Override
public void setActivated(final boolean activated) {
setActivated(activated, true);
}
@Override
public void onActionExecuted(final Action action) {
if(action instanceof LoadDrawing) {
currentFile = ((LoadDrawing) action).getFile();
if(currentFile != null) {
currentFolder = currentFile.getParentFile();
}
}
}
@Override
protected void configureBindings() throws IllegalAccessException, InstantiationException {
final BiFunction<SaveDrawing, FileLoaderSaver, Void> initSaveAction = (action, instrument) -> {
initIOAction.apply(action, instrument);
action.setFileChooser(instrument.getDialog(true));
action.setFile(instrument.currentFile);
action.setCurrentFolder(instrument.currentFolder);
action.setPrefSetter(prefSetter);
return null;
};
final Consumer<SaveDrawing> saveAction = action -> {
initSaveAction.apply(action, FileLoaderSaver.this);
action.setSaveAs(false);
action.setSaveOnClose(false);
};
final Consumer<LoadDrawing> loadAction = action -> {
initIOAction.apply(action, this);
action.setFileChooser(getDialog(false));
action.setCurrentFolder(currentFolder);
};
final Consumer<NewDrawing> newAction = action -> {
initIOAction.apply(action, this);
action.setPrefSetter(prefSetter);
action.setFileChooser(getDialog(false));
action.setCurrentFolder(currentFolder);
};
// Close window
bindWindow(SaveDrawing.class, action -> {
initSaveAction.apply(action, FileLoaderSaver.this);
action.setSaveAs(true);
action.setSaveOnClose(true);
}, WindowClosed.class, LaTeXDraw.getINSTANCE().getMainStage());
// Quit shortcut
bindKeyShortcut(Arrays.asList(KeyCode.W, LSystem.INSTANCE.getControlKey()), SaveDrawing.class, action -> {
initSaveAction.apply(action, FileLoaderSaver.this);
action.setSaveAs(true);
action.setSaveOnClose(true);
}, LaTeXDraw.getINSTANCE().getMainStage());
// Save menu
bindMenu(SaveDrawing.class, saveAction, saveMenu);
// Save shortcut
bindKeyShortcut(Arrays.asList(KeyCode.S, LSystem.INSTANCE.getControlKey()), SaveDrawing.class, saveAction, LaTeXDraw
.getINSTANCE().getMainStage());
// Save as menu
bindMenu(SaveDrawing.class, action -> {
initSaveAction.apply(action, FileLoaderSaver.this);
action.setSaveAs(true);
action.setSaveOnClose(false);
action.setFile(null);
}, saveAsMenu);
// Load menu
bindMenu(LoadDrawing.class, loadAction, loadMenu);
// Load shortcut
bindKeyShortcut(Arrays.asList(KeyCode.O, LSystem.INSTANCE.getControlKey()), LoadDrawing.class, loadAction, LaTeXDraw
.getINSTANCE().getMainStage());
// New menu
bindMenu(NewDrawing.class, newAction, newMenu);
// New shortcut
bindKeyShortcut(Arrays.asList(KeyCode.N, LSystem.INSTANCE.getControlKey()), NewDrawing.class, newAction, LaTeXDraw
.getINSTANCE().getMainStage());
// Recent files menus
recentInterator = new RecentMenuItem2LoadInteractor(this);
addBinding(recentInterator);
}
/**
* @return The path where documents are saved.
*/
public String getPathSave() {
return pathSave;
}
/**
* Sets the path where documents are saved.
* @param path The path where documents are saved.
*/
public void setPathSave(final String path) {
if(path != null && new File(path).isDirectory()) {
pathSave = path;
}
}
/**
* @return The current file loaded or saved.
*/
public File getCurrentFile() {
return currentFile;
}
/**
* Sets the current file loaded or saved.
* @param file The current file loaded or saved.
*/
public void setCurrentFile(final File file) {
if(file != null) {
currentFile = file;
}
}
/**
* Updates the recent menu items.
* @param recentDocs The list of recent documents.
*/
public void updateRecentMenuItems(final List<String> recentDocs) {
// Clean menus before removing them?
recentFilesMenu.getItems().clear();
if(recentDocs != null && !recentDocs.isEmpty()) {
recentDocs.forEach(fileName -> {
final MenuItem item = new MenuItem(new File(fileName).getName());
item.setUserData(fileName);
recentFilesMenu.getItems().add(item);
});
if(recentInterator != null) {
recentInterator.getInteraction().registerToMenuItems(recentFilesMenu.getItems());
}
}
recentFilesMenu.setDisable(recentFilesMenu.getItems().isEmpty());
}
/**
* @param save True: the dialogue box will be configured in a saving purpose. Otherwise, in an loading purpose.
* @return The dialogue box to open or save drawings.
*/
public FileChooser getDialog(final boolean save) {
if(fileChooser == null) {
fileChooser = new FileChooser();
fileChooser.getExtensionFilters().clear();
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("SVG", "*.svg")); //$NON-NLS-1$ //$NON-NLS-2$
}
fileChooser.setTitle(save ? LangTool.INSTANCE.getBundle().getString("LaTeXDrawFrame.188") : //$NON-NLS-1$
LangTool.INSTANCE.getBundle().getString("LaTeXDrawFrame.200")); //$NON-NLS-1$
return fileChooser;
}
@Override
public void save(final boolean generalPreferences, final String nsURI, final Document document, final Element root) {
super.save(generalPreferences, nsURI, document, root);
if(generalPreferences && document != null && root != null) {
final Element elt = document.createElement(LNamespace.XML_PATH_OPEN);
elt.setTextContent(pathSave);
root.appendChild(elt);
}
}
@Override
public void initialize(final URL location, final ResourceBundle resources) {
setActivated(true);
}
private static final class RecentMenuItem2LoadInteractor extends JfxMenuItemBinding<LoadDrawing, MenuItemPressed, FileLoaderSaver> {
private RecentMenuItem2LoadInteractor(final FileLoaderSaver ins) throws InstantiationException, IllegalAccessException {
super(ins, false, LoadDrawing.class, MenuItemPressed.class);
}
@Override
public void initAction() {
initIOAction.apply(action, instrument);
action.setFileChooser(instrument.getDialog(false));
action.setCurrentFolder(instrument.currentFolder);
action.setFile(new File((String) interaction.getWidget().getUserData()));
}
}
}