Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git

Started to make resource properties consistent.

Authordjarvis <email>
Date2016-10-20 19:55:10 GMT-0700
Commit6c6fb794ea0fbd2c5c575dd7e1cebc0f3e36bdb1
Parentda1354d
USAGE.Rmd
+# Introduction
+
+This document describes how to write documentation (technical or
+otherwise) using a one master copy and produce a variety of output
+formats, such as: HTML pages, PDFs, and EPUBs. What's more, the
+document provides an overview of how to use variables and--for the
+unintimidated--leverage the power of R, a programming language.
+
+# Software Requirements
+
+Install Java, ConTeXt, Pandoc, R, and Lib V8. Then install the R
+packages knitr, yaml, and devtools, and pluralize by running the
+following commands:
+
+ sudo su -
+ apt-get install default-jre
+ apt-get install context
+ apt-get install pandoc
+ apt-get install r
+ apt-get install libv8-dev
+ r
+ url <- "http://cran.us.r-project.org"
+ install.packages('knitr', repos=url)
+ install.packages('yaml', repos=url)
+ install.packages('devtools', repos=url)
+ devtools::install_github("hrbrmstr/pluralize")
+
+To exit R, press `Ctrl+d` or type `q()` followed by pressing `Enter`.
+
+The required software packages are installed.
+
+# Markdown
+
+
+
src/main/java/com/scrivendor/FileEditor.java
void load() {
- Path filePath = this.path.get();
+ final Path filePath = this.path.get();
if( filePath != null ) {
try {
byte[] bytes = Files.readAllBytes( filePath );
String markdown;
try {
markdown = new String( bytes, getOptions().getEncoding() );
- } catch( Exception ex ) {
+ } catch( Exception e ) {
// Unsupported encodings and null pointers will fallback here.
markdown = new String( bytes );
boolean save() {
- String markdown = markdownEditorPane.getMarkdown();
+ final String markdown = markdownEditorPane.getMarkdown();
byte[] bytes;
src/main/java/com/scrivendor/Main.java
private String getApplicationTitle() {
- return Messages.get( "Application.title" );
+ return Messages.get( "Main.title" );
}
src/main/java/com/scrivendor/MainWindow.java
import static com.scrivendor.Constants.LOGO_32;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.BOLD;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.CODE;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FILE_ALT;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FILE_CODE_ALT;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FLOPPY_ALT;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FOLDER_OPEN_ALT;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.HEADER;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.ITALIC;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.LINK;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.LIST_OL;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.LIST_UL;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.PICTURE_ALT;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.QUOTE_LEFT;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.REPEAT;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.STRIKETHROUGH;
-import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.UNDO;
-import java.text.MessageFormat;
-import java.util.function.Function;
-import javafx.beans.binding.Bindings;
-import javafx.beans.binding.BooleanBinding;
-import javafx.beans.property.BooleanProperty;
-import javafx.beans.property.SimpleBooleanProperty;
-import javafx.beans.value.ObservableBooleanValue;
-import javafx.event.Event;
-import javafx.scene.Node;
-import javafx.scene.Scene;
-import javafx.scene.control.Alert;
-import javafx.scene.control.Alert.AlertType;
-import javafx.scene.control.Menu;
-import javafx.scene.control.MenuBar;
-import javafx.scene.control.ToolBar;
-import javafx.scene.image.Image;
-import javafx.scene.image.ImageView;
-import static javafx.scene.input.KeyCode.ESCAPE;
-import javafx.scene.input.KeyEvent;
-import static javafx.scene.input.KeyEvent.CHAR_UNDEFINED;
-import static javafx.scene.input.KeyEvent.KEY_PRESSED;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.layout.VBox;
-import javafx.stage.Window;
-import javafx.stage.WindowEvent;
-import com.scrivendor.editor.MarkdownEditorPane;
-import com.scrivendor.options.OptionsDialog;
-import com.scrivendor.util.Action;
-import com.scrivendor.util.ActionUtils;
-
-/**
- * Main window containing a tab pane in the center for file editors.
- *
- * @author Karl Tauber
- */
-class MainWindow {
-
- private final Scene scene;
- private final FileEditorTabPane fileEditorTabPane;
- private MenuBar menuBar;
-
- MainWindow() {
- this.fileEditorTabPane = new FileEditorTabPane( this );
-
- BorderPane borderPane = new BorderPane();
- borderPane.setPrefSize( 800, 800 );
- borderPane.setTop( createMenuBarAndToolBar() );
- borderPane.setCenter( fileEditorTabPane.getNode() );
-
- this.scene = new Scene( borderPane );
- this.scene.getStylesheets().add( Constants.STYLESHEET_PREVIEW );
- this.scene.windowProperty().addListener( (observable, oldWindow, newWindow) -> {
- newWindow.setOnCloseRequest( e -> {
- if( !this.fileEditorTabPane.closeAllEditors() ) {
- e.consume();
- }
- } );
-
- // workaround for a bug in JavaFX: unselect menubar if window looses focus
- newWindow.focusedProperty().addListener( (obs, oldFocused, newFocused) -> {
- if( !newFocused ) {
- // send an ESC key event to the menubar
- this.menuBar.fireEvent( new KeyEvent( KEY_PRESSED, CHAR_UNDEFINED, "", ESCAPE,
- false, false, false, false ) );
- }
- } );
- } );
-
- }
-
- Scene getScene() {
- return scene;
- }
-
- private Node createMenuBarAndToolBar() {
- BooleanBinding activeFileEditorIsNull = fileEditorTabPane.activeFileEditorProperty().isNull();
-
- // File actions
- Action fileNewAction = new Action( Messages.get( "MainWindow.fileNewAction" ), "Shortcut+N", FILE_ALT, e -> fileNew() );
- Action fileOpenAction = new Action( Messages.get( "MainWindow.fileOpenAction" ), "Shortcut+O", FOLDER_OPEN_ALT, e -> fileOpen() );
- Action fileCloseAction = new Action( Messages.get( "MainWindow.fileCloseAction" ), "Shortcut+W", null, e -> fileClose(), activeFileEditorIsNull );
- Action fileCloseAllAction = new Action( Messages.get( "MainWindow.fileCloseAllAction" ), null, null, e -> fileCloseAll(), activeFileEditorIsNull );
- Action fileSaveAction = new Action( Messages.get( "MainWindow.fileSaveAction" ), "Shortcut+S", FLOPPY_ALT, e -> fileSave(),
- createActiveBooleanProperty( FileEditor::modifiedProperty ).not() );
- Action fileSaveAllAction = new Action( Messages.get( "MainWindow.fileSaveAllAction" ), "Shortcut+Shift+S", null, e -> fileSaveAll(),
- Bindings.not( fileEditorTabPane.anyFileEditorModifiedProperty() ) );
- Action fileExitAction = new Action( Messages.get( "MainWindow.fileExitAction" ), null, null, e -> fileExit() );
-
- // Edit actions
- Action editUndoAction = new Action( Messages.get( "MainWindow.editUndoAction" ), "Shortcut+Z", UNDO,
- e -> getActiveEditor().undo(),
- createActiveBooleanProperty( FileEditor::canUndoProperty ).not() );
- Action editRedoAction = new Action( Messages.get( "MainWindow.editRedoAction" ), "Shortcut+Y", REPEAT,
- e -> getActiveEditor().redo(),
- createActiveBooleanProperty( FileEditor::canRedoProperty ).not() );
-
- // Insert actions
- Action insertBoldAction = new Action( Messages.get( "MainWindow.insertBoldAction" ), "Shortcut+B", BOLD,
- e -> getActiveEditor().surroundSelection( "**", "**" ),
- activeFileEditorIsNull );
- Action insertItalicAction = new Action( Messages.get( "MainWindow.insertItalicAction" ), "Shortcut+I", ITALIC,
- e -> getActiveEditor().surroundSelection( "*", "*" ),
- activeFileEditorIsNull );
- Action insertStrikethroughAction = new Action( Messages.get( "MainWindow.insertStrikethroughAction" ), "Shortcut+T", STRIKETHROUGH,
- e -> getActiveEditor().surroundSelection( "~~", "~~" ),
- activeFileEditorIsNull );
- Action insertBlockquoteAction = new Action( Messages.get( "MainWindow.insertBlockquoteAction" ), "Ctrl+Q", QUOTE_LEFT, // not Shortcut+Q because of conflict on Mac
- e -> getActiveEditor().surroundSelection( "\n\n> ", "" ),
- activeFileEditorIsNull );
- Action insertCodeAction = new Action( Messages.get( "MainWindow.insertCodeAction" ), "Shortcut+K", CODE,
- e -> getActiveEditor().surroundSelection( "`", "`" ),
- activeFileEditorIsNull );
- Action insertFencedCodeBlockAction = new Action( Messages.get( "MainWindow.insertFencedCodeBlockAction" ), "Shortcut+Shift+K", FILE_CODE_ALT,
- e -> getActiveEditor().surroundSelection( "\n\n```\n", "\n```\n\n", Messages.get( "MainWindow.insertFencedCodeBlockText" ) ),
- activeFileEditorIsNull );
-
- Action insertLinkAction = new Action( Messages.get( "MainWindow.insertLinkAction" ), "Shortcut+L", LINK,
- e -> getActiveEditor().insertLink(),
- activeFileEditorIsNull );
- Action insertImageAction = new Action( Messages.get( "MainWindow.insertImageAction" ), "Shortcut+G", PICTURE_ALT,
- e -> getActiveEditor().insertImage(),
- activeFileEditorIsNull );
-
- Action insertHeader1Action = new Action( Messages.get( "MainWindow.insertHeader1Action" ), "Shortcut+1", HEADER,
- e -> getActiveEditor().surroundSelection( "\n\n# ", "", Messages.get( "MainWindow.insertHeader1Text" ) ),
- activeFileEditorIsNull );
- Action insertHeader2Action = new Action( Messages.get( "MainWindow.insertHeader2Action" ), "Shortcut+2", HEADER,
- e -> getActiveEditor().surroundSelection( "\n\n## ", "", Messages.get( "MainWindow.insertHeader2Text" ) ),
- activeFileEditorIsNull );
- Action insertHeader3Action = new Action( Messages.get( "MainWindow.insertHeader3Action" ), "Shortcut+3", HEADER,
- e -> getActiveEditor().surroundSelection( "\n\n### ", "", Messages.get( "MainWindow.insertHeader3Text" ) ),
- activeFileEditorIsNull );
- Action insertHeader4Action = new Action( Messages.get( "MainWindow.insertHeader4Action" ), "Shortcut+4", HEADER,
- e -> getActiveEditor().surroundSelection( "\n\n#### ", "", Messages.get( "MainWindow.insertHeader4Text" ) ),
- activeFileEditorIsNull );
- Action insertHeader5Action = new Action( Messages.get( "MainWindow.insertHeader5Action" ), "Shortcut+5", HEADER,
- e -> getActiveEditor().surroundSelection( "\n\n##### ", "", Messages.get( "MainWindow.insertHeader5Text" ) ),
- activeFileEditorIsNull );
- Action insertHeader6Action = new Action( Messages.get( "MainWindow.insertHeader6Action" ), "Shortcut+6", HEADER,
- e -> getActiveEditor().surroundSelection( "\n\n###### ", "", Messages.get( "MainWindow.insertHeader6Text" ) ),
- activeFileEditorIsNull );
-
- Action insertUnorderedListAction = new Action( Messages.get( "MainWindow.insertUnorderedListAction" ), "Shortcut+U", LIST_UL,
- e -> getActiveEditor().surroundSelection( "\n\n* ", "" ),
- activeFileEditorIsNull );
- Action insertOrderedListAction = new Action( Messages.get( "MainWindow.insertOrderedListAction" ), "Shortcut+Shift+O", LIST_OL,
- e -> getActiveEditor().surroundSelection( "\n\n1. ", "" ),
- activeFileEditorIsNull );
- Action insertHorizontalRuleAction = new Action( Messages.get( "MainWindow.insertHorizontalRuleAction" ), "Shortcut+H", null,
- e -> getActiveEditor().surroundSelection( "\n\n---\n\n", "" ),
- activeFileEditorIsNull );
-
- // Tools actions
- Action toolsOptionsAction = new Action( Messages.get( "MainWindow.toolsOptionsAction" ), "Shortcut+,", null, e -> toolsOptions() );
-
- // Help actions
- Action helpAboutAction = new Action( Messages.get( "MainWindow.helpAboutAction" ), null, null, e -> helpAbout() );
-
- //---- MenuBar ----
- Menu fileMenu = ActionUtils.createMenu( Messages.get( "MainWindow.fileMenu" ),
- fileNewAction,
- fileOpenAction,
- null,
- fileCloseAction,
- fileCloseAllAction,
- null,
- fileSaveAction,
- fileSaveAllAction,
- null,
- fileExitAction );
-
- Menu editMenu = ActionUtils.createMenu( Messages.get( "MainWindow.editMenu" ),
- editUndoAction,
- editRedoAction );
-
- Menu insertMenu = ActionUtils.createMenu( Messages.get( "MainWindow.insertMenu" ),
- insertBoldAction,
- insertItalicAction,
- insertStrikethroughAction,
- insertBlockquoteAction,
- insertCodeAction,
- insertFencedCodeBlockAction,
- null,
- insertLinkAction,
- insertImageAction,
- null,
- insertHeader1Action,
- insertHeader2Action,
- insertHeader3Action,
- insertHeader4Action,
- insertHeader5Action,
- insertHeader6Action,
- null,
- insertUnorderedListAction,
- insertOrderedListAction,
- insertHorizontalRuleAction );
-
- Menu toolsMenu = ActionUtils.createMenu( Messages.get( "MainWindow.toolsMenu" ),
- toolsOptionsAction );
-
- Menu helpMenu = ActionUtils.createMenu( Messages.get( "MainWindow.helpMenu" ),
- helpAboutAction );
-
- menuBar = new MenuBar( fileMenu, editMenu, insertMenu, toolsMenu, helpMenu );
-
- //---- ToolBar ----
- ToolBar toolBar = ActionUtils.createToolBar(
- fileNewAction,
- fileOpenAction,
- fileSaveAction,
- null,
- editUndoAction,
- editRedoAction,
- null,
- insertBoldAction,
- insertItalicAction,
- insertBlockquoteAction,
- insertCodeAction,
- insertFencedCodeBlockAction,
- null,
- insertLinkAction,
- insertImageAction,
- null,
- insertHeader1Action,
- null,
- insertUnorderedListAction,
- insertOrderedListAction );
-
- return new VBox( menuBar, toolBar );
- }
-
- private MarkdownEditorPane getActiveEditor() {
- return fileEditorTabPane.getActiveFileEditor().getEditor();
- }
-
- /**
- * Creates a boolean property that is bound to another boolean value of the
- * active editor.
- */
- private BooleanProperty createActiveBooleanProperty( Function<FileEditor, ObservableBooleanValue> func ) {
- BooleanProperty b = new SimpleBooleanProperty();
- FileEditor fileEditor = fileEditorTabPane.getActiveFileEditor();
- if( fileEditor != null ) {
- b.bind( func.apply( fileEditor ) );
- }
- fileEditorTabPane.activeFileEditorProperty().addListener( (observable, oldFileEditor, newFileEditor) -> {
- b.unbind();
- if( newFileEditor != null ) {
- b.bind( func.apply( newFileEditor ) );
- } else {
- b.set( false );
- }
- } );
- return b;
- }
-
- Alert createAlert( AlertType alertType, String title,
- String contentTextFormat, Object... contentTextArgs ) {
- Alert alert = new Alert( alertType );
- alert.setTitle( title );
- alert.setHeaderText( null );
- alert.setContentText( MessageFormat.format( contentTextFormat, contentTextArgs ) );
- alert.initOwner( getScene().getWindow() );
- return alert;
- }
-
- //---- File actions -------------------------------------------------------
- private void fileNew() {
- fileEditorTabPane.newEditor();
- }
-
- private void fileOpen() {
- fileEditorTabPane.openEditor();
- }
-
- private void fileClose() {
- fileEditorTabPane.closeEditor( fileEditorTabPane.getActiveFileEditor(), true );
- }
-
- private void fileCloseAll() {
- fileEditorTabPane.closeAllEditors();
- }
-
- private void fileSave() {
- fileEditorTabPane.saveEditor( fileEditorTabPane.getActiveFileEditor() );
- }
-
- private void fileSaveAll() {
- fileEditorTabPane.saveAllEditors();
- }
-
- private void fileExit() {
- Window window = scene.getWindow();
- Event.fireEvent( window, new WindowEvent( window, WindowEvent.WINDOW_CLOSE_REQUEST ) );
- }
-
- //---- Tools actions ------------------------------------------------------
- private void toolsOptions() {
- OptionsDialog dialog = new OptionsDialog( getScene().getWindow() );
- dialog.showAndWait();
- }
-
- //---- Help actions -------------------------------------------------------
- private void helpAbout() {
- Alert alert = new Alert( AlertType.INFORMATION );
- alert.setTitle( Messages.get( "MainWindow.about.title" ) );
- alert.setHeaderText( Messages.get( "MainWindow.about.headerText" ) );
- alert.setContentText( Messages.get( "MainWindow.about.contentText" ) );
+import com.scrivendor.editor.MarkdownEditorPane;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.BOLD;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.CODE;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FILE_ALT;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FILE_CODE_ALT;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FLOPPY_ALT;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.FOLDER_OPEN_ALT;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.HEADER;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.ITALIC;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.LINK;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.LIST_OL;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.LIST_UL;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.PICTURE_ALT;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.QUOTE_LEFT;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.REPEAT;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.STRIKETHROUGH;
+import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.UNDO;
+import java.text.MessageFormat;
+import java.util.function.Function;
+import javafx.beans.binding.Bindings;
+import javafx.beans.binding.BooleanBinding;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.value.ObservableBooleanValue;
+import javafx.event.Event;
+import javafx.scene.Node;
+import javafx.scene.Scene;
+import javafx.scene.control.Alert;
+import javafx.scene.control.Alert.AlertType;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuBar;
+import javafx.scene.control.ToolBar;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import static javafx.scene.input.KeyCode.ESCAPE;
+import javafx.scene.input.KeyEvent;
+import static javafx.scene.input.KeyEvent.CHAR_UNDEFINED;
+import static javafx.scene.input.KeyEvent.KEY_PRESSED;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.VBox;
+import javafx.stage.Window;
+import javafx.stage.WindowEvent;
+import com.scrivendor.options.OptionsDialog;
+import com.scrivendor.util.Action;
+import com.scrivendor.util.ActionUtils;
+
+/**
+ * Main window containing a tab pane in the center for file editors.
+ *
+ * @author Karl Tauber
+ */
+class MainWindow {
+
+ private final Scene scene;
+ private final FileEditorTabPane fileEditorTabPane;
+ private MenuBar menuBar;
+
+ MainWindow() {
+ this.fileEditorTabPane = new FileEditorTabPane( this );
+
+ BorderPane borderPane = new BorderPane();
+ borderPane.setPrefSize( 800, 800 );
+ borderPane.setTop( createMenuBarAndToolBar() );
+ borderPane.setCenter( fileEditorTabPane.getNode() );
+
+ this.scene = new Scene( borderPane );
+ this.scene.getStylesheets().add( Constants.STYLESHEET_PREVIEW );
+ this.scene.windowProperty().addListener( (observable, oldWindow, newWindow) -> {
+ newWindow.setOnCloseRequest( e -> {
+ if( !this.fileEditorTabPane.closeAllEditors() ) {
+ e.consume();
+ }
+ } );
+
+ // workaround for a bug in JavaFX: unselect menubar if window looses focus
+ newWindow.focusedProperty().addListener( (obs, oldFocused, newFocused) -> {
+ if( !newFocused ) {
+ // send an ESC key event to the menubar
+ this.menuBar.fireEvent( new KeyEvent( KEY_PRESSED, CHAR_UNDEFINED, "", ESCAPE,
+ false, false, false, false ) );
+ }
+ } );
+ } );
+
+ }
+
+ Scene getScene() {
+ return scene;
+ }
+
+ private Node createMenuBarAndToolBar() {
+ BooleanBinding activeFileEditorIsNull = fileEditorTabPane.activeFileEditorProperty().isNull();
+
+ // File actions
+ Action fileNewAction = new Action( Messages.get( "Main.menu.file.new" ), "Shortcut+N", FILE_ALT, e -> fileNew() );
+ Action fileOpenAction = new Action( Messages.get( "Main.menu.file.open" ), "Shortcut+O", FOLDER_OPEN_ALT, e -> fileOpen() );
+ Action fileCloseAction = new Action( Messages.get( "Main.menu.file.close" ), "Shortcut+W", null, e -> fileClose(), activeFileEditorIsNull );
+ Action fileCloseAllAction = new Action( Messages.get( "Main.menu.file.close_all" ), null, null, e -> fileCloseAll(), activeFileEditorIsNull );
+ Action fileSaveAction = new Action( Messages.get( "Main.menu.file.save" ), "Shortcut+S", FLOPPY_ALT, e -> fileSave(),
+ createActiveBooleanProperty( FileEditor::modifiedProperty ).not() );
+ Action fileSaveAllAction = new Action( Messages.get( "Main.menu.file.save_all" ), "Shortcut+Shift+S", null, e -> fileSaveAll(),
+ Bindings.not( fileEditorTabPane.anyFileEditorModifiedProperty() ) );
+ Action fileExitAction = new Action( Messages.get( "Main.menu.file.exit" ), null, null, e -> fileExit() );
+
+ // Edit actions
+ Action editUndoAction = new Action( Messages.get( "Main.menu.edit.undo" ), "Shortcut+Z", UNDO,
+ e -> getActiveEditor().undo(),
+ createActiveBooleanProperty( FileEditor::canUndoProperty ).not() );
+ Action editRedoAction = new Action( Messages.get( "Main.menu.edit.redo" ), "Shortcut+Y", REPEAT,
+ e -> getActiveEditor().redo(),
+ createActiveBooleanProperty( FileEditor::canRedoProperty ).not() );
+
+ // Insert actions
+ Action insertBoldAction = new Action( Messages.get( "Main.menu.insert.bold" ), "Shortcut+B", BOLD,
+ e -> getActiveEditor().surroundSelection( "**", "**" ),
+ activeFileEditorIsNull );
+ Action insertItalicAction = new Action( Messages.get( "Main.menu.insert.italic" ), "Shortcut+I", ITALIC,
+ e -> getActiveEditor().surroundSelection( "*", "*" ),
+ activeFileEditorIsNull );
+ Action insertStrikethroughAction = new Action( Messages.get( "Main.menu.insert.strikethrough" ), "Shortcut+T", STRIKETHROUGH,
+ e -> getActiveEditor().surroundSelection( "~~", "~~" ),
+ activeFileEditorIsNull );
+ Action insertBlockquoteAction = new Action( Messages.get( "Main.menu.insert.blockquote" ), "Ctrl+Q", QUOTE_LEFT, // not Shortcut+Q because of conflict on Mac
+ e -> getActiveEditor().surroundSelection( "\n\n> ", "" ),
+ activeFileEditorIsNull );
+ Action insertCodeAction = new Action( Messages.get( "Main.menu.insert.code" ), "Shortcut+K", CODE,
+ e -> getActiveEditor().surroundSelection( "`", "`" ),
+ activeFileEditorIsNull );
+ Action insertFencedCodeBlockAction = new Action( Messages.get( "Main.menu.insert.fenced_code_block" ), "Shortcut+Shift+K", FILE_CODE_ALT,
+ e -> getActiveEditor().surroundSelection( "\n\n```\n", "\n```\n\n", Messages.get( "Main.menu.insert.fenced_code_block.prompt" ) ),
+ activeFileEditorIsNull );
+
+ Action insertLinkAction = new Action( Messages.get( "Main.menu.insert.link" ), "Shortcut+L", LINK,
+ e -> getActiveEditor().insertLink(),
+ activeFileEditorIsNull );
+ Action insertImageAction = new Action( Messages.get( "Main.menu.insert.image" ), "Shortcut+G", PICTURE_ALT,
+ e -> getActiveEditor().insertImage(),
+ activeFileEditorIsNull );
+
+ final Action[] headers = new Action[ 6 ];
+
+ for( int i = 1; i <= 6; i++ ) {
+ final String hashes = new String( new char[ i ] ).replace( "\0", "#" );
+ final String markup = String.format( "\n\n%s ", hashes );
+ final String text = Messages.get( "Main.menu.insert.header_" + i );
+ final String accelerator = "Shortcut+" + i;
+ final String prompt = Messages.get( "Main.menu.insert.header_" + i + ".prompt" );
+
+ headers[ i-1 ] = new Action( text, accelerator, HEADER,
+ e -> getActiveEditor().surroundSelection( markup, "", prompt ),
+ activeFileEditorIsNull );
+ }
+
+ Action insertUnorderedListAction = new Action( Messages.get( "Main.menu.insert.unordered_list" ), "Shortcut+U", LIST_UL,
+ e -> getActiveEditor().surroundSelection( "\n\n* ", "" ),
+ activeFileEditorIsNull );
+ Action insertOrderedListAction = new Action( Messages.get( "Main.menu.insert.ordered_list" ), "Shortcut+Shift+O", LIST_OL,
+ e -> getActiveEditor().surroundSelection( "\n\n1. ", "" ),
+ activeFileEditorIsNull );
+ Action insertHorizontalRuleAction = new Action( Messages.get( "Main.menu.insert.horizontal_rule" ), "Shortcut+H", null,
+ e -> getActiveEditor().surroundSelection( "\n\n---\n\n", "" ),
+ activeFileEditorIsNull );
+
+ // Tools actions
+ Action toolsOptionsAction = new Action( Messages.get( "Main.menu.tools.options" ), "Shortcut+,", null, e -> toolsOptions() );
+
+ // Help actions
+ Action helpAboutAction = new Action( Messages.get( "Main.menu.help.about" ), null, null, e -> helpAbout() );
+
+ //---- MenuBar ----
+ Menu fileMenu = ActionUtils.createMenu( Messages.get( "Main.menu.file" ),
+ fileNewAction,
+ fileOpenAction,
+ null,
+ fileCloseAction,
+ fileCloseAllAction,
+ null,
+ fileSaveAction,
+ fileSaveAllAction,
+ null,
+ fileExitAction );
+
+ Menu editMenu = ActionUtils.createMenu( Messages.get( "Main.menu.edit" ),
+ editUndoAction,
+ editRedoAction );
+
+ Menu insertMenu = ActionUtils.createMenu( Messages.get( "Main.menu.insert" ),
+ insertBoldAction,
+ insertItalicAction,
+ insertStrikethroughAction,
+ insertBlockquoteAction,
+ insertCodeAction,
+ insertFencedCodeBlockAction,
+ null,
+ insertLinkAction,
+ insertImageAction,
+ null,
+ headers[ 0 ],
+ headers[ 1 ],
+ headers[ 2 ],
+ headers[ 3 ],
+ headers[ 4 ],
+ headers[ 5 ],
+ null,
+ insertUnorderedListAction,
+ insertOrderedListAction,
+ insertHorizontalRuleAction );
+
+ Menu toolsMenu = ActionUtils.createMenu( Messages.get( "Main.menu.tools" ),
+ toolsOptionsAction );
+
+ Menu helpMenu = ActionUtils.createMenu( Messages.get( "Main.menu.help" ),
+ helpAboutAction );
+
+ menuBar = new MenuBar( fileMenu, editMenu, insertMenu, toolsMenu, helpMenu );
+
+ //---- ToolBar ----
+ ToolBar toolBar = ActionUtils.createToolBar(
+ fileNewAction,
+ fileOpenAction,
+ fileSaveAction,
+ null,
+ editUndoAction,
+ editRedoAction,
+ null,
+ insertBoldAction,
+ insertItalicAction,
+ insertBlockquoteAction,
+ insertCodeAction,
+ insertFencedCodeBlockAction,
+ null,
+ insertLinkAction,
+ insertImageAction,
+ null,
+ headers[ 0 ],
+ null,
+ insertUnorderedListAction,
+ insertOrderedListAction );
+
+ return new VBox( menuBar, toolBar );
+ }
+
+ private MarkdownEditorPane getActiveEditor() {
+ return fileEditorTabPane.getActiveFileEditor().getEditor();
+ }
+
+ /**
+ * Creates a boolean property that is bound to another boolean value of the
+ * active editor.
+ */
+ private BooleanProperty createActiveBooleanProperty( Function<FileEditor, ObservableBooleanValue> func ) {
+ BooleanProperty b = new SimpleBooleanProperty();
+ FileEditor fileEditor = fileEditorTabPane.getActiveFileEditor();
+ if( fileEditor != null ) {
+ b.bind( func.apply( fileEditor ) );
+ }
+ fileEditorTabPane.activeFileEditorProperty().addListener( (observable, oldFileEditor, newFileEditor) -> {
+ b.unbind();
+ if( newFileEditor != null ) {
+ b.bind( func.apply( newFileEditor ) );
+ } else {
+ b.set( false );
+ }
+ } );
+ return b;
+ }
+
+ Alert createAlert( AlertType alertType, String title,
+ String contentTextFormat, Object... contentTextArgs ) {
+ Alert alert = new Alert( alertType );
+ alert.setTitle( title );
+ alert.setHeaderText( null );
+ alert.setContentText( MessageFormat.format( contentTextFormat, contentTextArgs ) );
+ alert.initOwner( getScene().getWindow() );
+ return alert;
+ }
+
+ //---- File actions -------------------------------------------------------
+ private void fileNew() {
+ fileEditorTabPane.newEditor();
+ }
+
+ private void fileOpen() {
+ fileEditorTabPane.openEditor();
+ }
+
+ private void fileClose() {
+ fileEditorTabPane.closeEditor( fileEditorTabPane.getActiveFileEditor(), true );
+ }
+
+ private void fileCloseAll() {
+ fileEditorTabPane.closeAllEditors();
+ }
+
+ private void fileSave() {
+ fileEditorTabPane.saveEditor( fileEditorTabPane.getActiveFileEditor() );
+ }
+
+ private void fileSaveAll() {
+ fileEditorTabPane.saveAllEditors();
+ }
+
+ private void fileExit() {
+ Window window = scene.getWindow();
+ Event.fireEvent( window, new WindowEvent( window, WindowEvent.WINDOW_CLOSE_REQUEST ) );
+ }
+
+ //---- Tools actions ------------------------------------------------------
+ private void toolsOptions() {
+ OptionsDialog dialog = new OptionsDialog( getScene().getWindow() );
+ dialog.showAndWait();
+ }
+
+ //---- Help actions -------------------------------------------------------
+ private void helpAbout() {
+ Alert alert = new Alert( AlertType.INFORMATION );
+ alert.setTitle( Messages.get( "Dialog.about.title" ) );
+ alert.setHeaderText( Messages.get( "Dialog.about.header" ) );
+ alert.setContentText( Messages.get( "Dialog.about.content" ) );
alert.setGraphic( new ImageView( new Image( LOGO_32 ) ) );
alert.initOwner( getScene().getWindow() );
src/main/java/com/scrivendor/Messages.java
*/
public static String get( String key ) {
- return resolve( RESOURCE_BUNDLE, RESOURCE_BUNDLE.getString( key ) );
+ String result;
+
+ try {
+ result = resolve( RESOURCE_BUNDLE, RESOURCE_BUNDLE.getString( key ) );
+ } catch( Exception e ) {
+
+ // Instead of crashing, launch the application and show the resource
+ // name.
+ result = key;
+ }
+
+ return result;
}
src/main/resources/com/scrivendor/messages.properties
#
-#---- Application ----
+#---- Main Application Window ----
# The application title should exist only once in the entire code base.
# All other references should either refer to this value via the Messages
-# class, or indirectly using ${Application.title}.
-Application.title=Scrivendor
+# class, or indirectly using ${Main.title}.
+Main.title=Scrivendor
-#---- MainWindow ----
+Main.menu.file=_File
+Main.menu.file.new=New
+Main.menu.file.open=Open...
+Main.menu.file.close=Close
+Main.menu.file.close_all=Close All
+Main.menu.file.save=Save
+Main.menu.file.save_all=Save All
+Main.menu.file.exit=Exit
-MainWindow.fileMenu=_File
-MainWindow.fileNewAction=New
-MainWindow.fileOpenAction=Open...
-MainWindow.fileCloseAction=Close
-MainWindow.fileCloseAllAction=Close All
-MainWindow.fileSaveAction=Save
-MainWindow.fileSaveAllAction=Save All
-MainWindow.fileExitAction=Exit
+Main.menu.edit=_Edit
+Main.menu.edit.undo=Undo
+Main.menu.edit.redo=Redo
-MainWindow.editMenu=_Edit
-MainWindow.editUndoAction=Undo
-MainWindow.editRedoAction=Redo
+Main.menu.insert=_Insert
+Main.menu.insert.bold=Bold
+Main.menu.insert.italic=Italic
+Main.menu.insert.strikethrough=Strikethrough
+Main.menu.insert.blockquote=Blockquote
+Main.menu.insert.code=Inline Code
+Main.menu.insert.fenced_code_block=Fenced Code Block
+Main.menu.insert.fenced_code_block.prompt=Enter code here
+Main.menu.insert.link=Link...
+Main.menu.insert.image=Image...
+Main.menu.insert.header_1=Header 1
+Main.menu.insert.header_1.prompt=header 1
+Main.menu.insert.header_2=Header 2
+Main.menu.insert.header_2.prompt=header 2
+Main.menu.insert.header_3=Header 3
+Main.menu.insert.header_3.prompt=header 3
+Main.menu.insert.header_4=Header 4
+Main.menu.insert.header_4.prompt=header 4
+Main.menu.insert.header_5=Header 5
+Main.menu.insert.header_5.prompt=header 5
+Main.menu.insert.header_6=Header 6
+Main.menu.insert.header_6.prompt=header 6
+Main.menu.insert.unordered_list=Unordered List
+Main.menu.insert.ordered_list=Ordered List
+Main.menu.insert.horizontal_rule=Horizontal Rule
-MainWindow.insertMenu=_Insert
-MainWindow.insertBoldAction=Bold
-MainWindow.insertItalicAction=Italic
-MainWindow.insertStrikethroughAction=Strikethrough
-MainWindow.insertBlockquoteAction=Blockquote
-MainWindow.insertCodeAction=Inline Code
-MainWindow.insertFencedCodeBlockAction=Fenced Code Block
-MainWindow.insertFencedCodeBlockText=enter code here
-MainWindow.insertLinkAction=Link...
-MainWindow.insertImageAction=Image...
-MainWindow.insertHeader1Action=Header 1
-MainWindow.insertHeader1Text=header 1
-MainWindow.insertHeader2Action=Header 2
-MainWindow.insertHeader2Text=header 2
-MainWindow.insertHeader3Action=Header 3
-MainWindow.insertHeader3Text=header 3
-MainWindow.insertHeader4Action=Header 4
-MainWindow.insertHeader4Text=header 4
-MainWindow.insertHeader5Action=Header 5
-MainWindow.insertHeader5Text=header 5
-MainWindow.insertHeader6Action=Header 6
-MainWindow.insertHeader6Text=header 6
-MainWindow.insertUnorderedListAction=Unordered List
-MainWindow.insertOrderedListAction=Ordered List
-MainWindow.insertHorizontalRuleAction=Horizontal Rule
+Main.menu.tools=_Tools
+Main.menu.tools.options=Options
-MainWindow.toolsMenu=_Tools
-MainWindow.toolsOptionsAction=Options
+Main.menu.help=_Help
+Main.menu.help.about=About ${Main.title}
-MainWindow.helpMenu=_Help
-MainWindow.helpAboutAction=About ${Application.title}
+#---- About ----
-MainWindow.about.title=_About
-MainWindow.about.headerText=${Application.title}
-MainWindow.about.contentText=Copyright 2016 White Magic Software, Ltd.
+Dialog.about.title=About
+Dialog.about.header=${Main.title}
+Dialog.about.content=Copyright 2016 White Magic Software, Ltd.\n\nBased on Markdown Writer FX by Karl Tauber
#---- FileEditor ----
#---- BrowseDirectoryButton ----
-BrowseDirectoryButton.tooltip=Browse for local folder
BrowseDirectoryButton.chooser.title=Browse for local folder
+BrowseDirectoryButton.tooltip=${BrowseDirectoryButton.chooser.title}
#---- BrowseFileButton ----
-BrowseFileButton.tooltip=Browse for local file
BrowseFileButton.chooser.title=Browse for local file
BrowseFileButton.chooser.allFilesFilter=All Files
+BrowseFileButton.tooltip=${BrowseFileButton.chooser.title}
MarkdownOptionsPane.taskListItemsExtCheckBox.text=GitHub style task list items
MarkdownOptionsPane.wikilinksExtCheckBox.text=_Wiki-style links ("[[wiki link]]")
-
-
-#===== preview ================================================================
-
-#---- MarkdownPreviewPane ----
-
-MarkdownPreviewPane.astTab=Markdown AST
-MarkdownPreviewPane.htmlSourceTab=HTML Source
-MarkdownPreviewPane.webViewTab=Preview
Delta419 lines added, 387 lines removed, 32-line increase