package org.markdownwriterfx;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;
import java.nio.file.Path;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.SplitPane;
import javafx.scene.control.Tab;
import javafx.scene.control.Tooltip;
import javafx.scene.text.Text;
import org.fxmisc.undo.UndoManager;
import org.markdownwriterfx.editor.MarkdownEditorPane;
import org.markdownwriterfx.options.Options;
import org.markdownwriterfx.preview.MarkdownPreviewPane;
class FileEditor
{
private final MainWindow mainWindow;
private final Tab tab = new Tab();
private MarkdownEditorPane markdownEditorPane;
private MarkdownPreviewPane markdownPreviewPane;
FileEditor(MainWindow mainWindow, Path path) {
this.mainWindow = mainWindow;
this.path.set(path);
tab.setUserData(this);
this.path.addListener((observable, oldPath, newPath) -> updateTab());
this.modified.addListener((observable, oldPath, newPath) -> updateTab());
updateTab();
tab.setOnSelectionChanged(e -> {
if(tab.isSelected())
Platform.runLater(() -> activated());
});
}
Tab getTab() {
return tab;
}
MarkdownEditorPane getEditor() {
return markdownEditorPane;
}
private final ObjectProperty<Path> path = new SimpleObjectProperty<>();
Path getPath() { return path.get(); }
void setPath(Path path) { this.path.set(path); }
ObjectProperty<Path> pathProperty() { return path; }
private final ReadOnlyBooleanWrapper modified = new ReadOnlyBooleanWrapper();
boolean isModified() { return modified.get(); }
ReadOnlyBooleanProperty modifiedProperty() { return modified.getReadOnlyProperty(); }
private final BooleanProperty canUndo = new SimpleBooleanProperty();
BooleanProperty canUndoProperty() { return canUndo; }
private final BooleanProperty canRedo = new SimpleBooleanProperty();
BooleanProperty canRedoProperty() { return canRedo; }
private void updateTab() {
Path path = this.path.get();
tab.setText((path != null) ? path.getFileName().toString() : Messages.get("FileEditor.untitled"));
tab.setTooltip((path != null) ? new Tooltip(path.toString()) : null);
tab.setGraphic(isModified() ? new Text("*") : null);
}
private void activated() {
if( tab.getTabPane() == null || !tab.isSelected())
return;
if (tab.getContent() != null) {
markdownEditorPane.requestFocus();
return;
}
markdownEditorPane = new MarkdownEditorPane();
markdownPreviewPane = new MarkdownPreviewPane();
markdownEditorPane.pathProperty().bind(path);
load();
markdownEditorPane.getUndoManager().forgetHistory();
markdownPreviewPane.pathProperty().bind(pathProperty());
markdownPreviewPane.markdownASTProperty().bind(markdownEditorPane.markdownASTProperty());
markdownPreviewPane.scrollYProperty().bind(markdownEditorPane.scrollYProperty());
UndoManager undoManager = markdownEditorPane.getUndoManager();
modified.bind(Bindings.not(undoManager.atMarkedPositionProperty()));
canUndo.bind(undoManager.undoAvailableProperty());
canRedo.bind(undoManager.redoAvailableProperty());
SplitPane splitPane = new SplitPane(markdownEditorPane.getNode(), markdownPreviewPane.getNode());
tab.setContent(splitPane);
markdownEditorPane.requestFocus();
}
void load() {
Path path = this.path.get();
if (path == null)
return;
try {
byte[] bytes = Files.readAllBytes(path);
String markdown = null;
if (Options.getEncoding() != null) {
try {
markdown = new String(bytes, Options.getEncoding());
} catch (UnsupportedEncodingException ex) {
markdown = new String(bytes);
}
} else
markdown = new String(bytes);
markdownEditorPane.setMarkdown(markdown);
markdownEditorPane.getUndoManager().mark();
} catch (IOException ex) {
Alert alert = mainWindow.createAlert(AlertType.ERROR,
Messages.get("FileEditor.loadFailed.title"),
Messages.get("FileEditor.loadFailed.message"), path, ex.getMessage());
alert.showAndWait();
}
}
boolean save() {
String markdown = markdownEditorPane.getMarkdown();
byte[] bytes;
if (Options.getEncoding() != null) {
try {
bytes = markdown.getBytes(Options.getEncoding());
} catch (UnsupportedEncodingException ex) {
bytes = markdown.getBytes();
}
} else
bytes = markdown.getBytes();
try {
Files.write(path.get(), bytes);
markdownEditorPane.getUndoManager().mark();
return true;
} catch (IOException ex) {
Alert alert = mainWindow.createAlert(AlertType.ERROR,
Messages.get("FileEditor.saveFailed.title"),
Messages.get("FileEditor.saveFailed.message"), path.get(), ex.getMessage());
alert.showAndWait();
return false;
}
}
}