Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/keenwrite.git
M CHANGES.md
22
=============================
33
4
## 0.2
5
- RichTextFX (and dependencies) updated to versoin 0.6.10 (fixes bugs and memory leaks).
6
- pegdown Markdown parser updated to version 1.6.
7
- Added five new pegdown 1.6 extension flags to Markdown Options tab.
8
- Minor improvements.
9
410
## 0.1
511
- Initial release
A Markdown Writer FX.jfdproj
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project>
3
  <entry key="classpath1" value="bin" />
4
  <entry key="classpath2" value="lib/fontawesomefx-8.9.jar" />
5
  <entry key="sourcefolders1" value="src/main/java" />
6
  <entry key="sourcefolders2" value="src/main/resources" />
7
  <node name="designer">
8
    <entry key="_i18nJavaSettingsEnabled" value="true" />
9
    <entry key="_i18nSettingsEnabled" value="true" />
10
    <entry key="i18n.externalizeexcludes1" value="org.markdownwriterfx.controls.EscapeTextField#escapeCharacters" />
11
    <entry key="i18n.externalizeexcludes2" value="org.markdownwriterfx.controls.WebHyperlink#uri" />
12
    <entry key="i18n.javagetstringformat" value="Messages.get(${key})" />
13
  </node>
14
  <node name="javacodegenerator">
15
    <entry key="_codeStyleSettingsEnabled" value="true" />
16
    <entry key="_generalSettingsEnabled" value="true" />
17
    <entry key="explicitimports" value="true" />
18
    <entry key="lineseparator" value="\n" />
19
  </node>
20
</project>
21
122
M README.md
4141
------------
4242
43
Download markdown-writer-fx.zip and extract it to any folder.
43
Download
44
[markdown-writer-fx-0.2.zip](https://github.com/JFormDesigner/markdown-writer-fx/releases/download/0.2/markdown-writer-fx-0.2.zip)
45
and extract it to any folder.
4446
4547
Double-click `markdown-writer-fx.jar` to start *Markdown Writer FX*.
...
6062
6163
  * Tomas Mikula for [RichTextFX], [ReactFX], [WellBehavedFX], [Flowless] and [UndoFX]
62
  * Mikael Grev for [MigLayout] and Tom Eugelink and MigPane
64
  * Mikael Grev for [MigLayout] and Tom Eugelink for MigPane
6365
  * sirthias for [pegdown] Markdown parser
6466
  * Jens Deters for [FontAwesomeFX]
M build.gradle
1
version = '0.1'
1
version = '0.2'
22
33
apply plugin: 'java'
44
apply plugin: 'java-library-distribution'
55
66
repositories {
77
	mavenCentral()
88
}
99
1010
dependencies {
11
	compile group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.6.6'
11
	compile group: 'org.fxmisc.richtext', name: 'richtextfx', version: '0.6.10'
1212
	compile group: 'com.miglayout', name: 'miglayout-javafx', version: '5.0'
13
	compile group: 'de.jensd', name: 'fontawesomefx', version: '8.4'
14
	compile group: 'org.pegdown', name: 'pegdown', version: '1.5.0'
13
	compile group: 'de.jensd', name: 'fontawesomefx', version: '8.9'
14
	compile group: 'org.pegdown', name: 'pegdown', version: '1.6.0'
1515
1616
	// newer versions of dependencies
...
3333
		contents {
3434
			from { ['LICENSE', 'README.md'] }
35
			into( 'images' ) {
36
				from { 'images' }
37
			}
3538
		}
3639
	}
M images/screenshot.png
Binary file
M src/main/java/org/markdownwriterfx/FileEditor.java
4242
import javafx.scene.control.Alert;
4343
import javafx.scene.control.Alert.AlertType;
44
import javafx.scene.control.SingleSelectionModel;
45
import javafx.scene.input.KeyCode;
46
import javafx.scene.input.KeyCombination;
4744
import javafx.scene.control.SplitPane;
4845
import javafx.scene.control.Tab;
49
import javafx.scene.control.TabPane;
5046
import javafx.scene.control.Tooltip;
5147
import javafx.scene.text.Text;
5248
import org.fxmisc.undo.UndoManager;
53
import org.fxmisc.wellbehaved.event.EventHandlerHelper;
54
import org.fxmisc.wellbehaved.event.EventPattern;
5549
import org.markdownwriterfx.editor.MarkdownEditorPane;
5650
import org.markdownwriterfx.options.Options;
...
115109
	private void updateTab() {
116110
		Path path = this.path.get();
117
		tab.setText((path != null) ? path.getFileName().toString() : "Untitled");
111
		tab.setText((path != null) ? path.getFileName().toString() : Messages.get("FileEditor.untitled"));
118112
		tab.setTooltip((path != null) ? new Tooltip(path.toString()) : null);
119113
		tab.setGraphic(isModified() ? new Text("*") : null);
120
	}
121
122
	private void selectNextPreviousTab(int offset) {
123
		TabPane tabPane = tab.getTabPane();
124
		SingleSelectionModel<Tab> selectionModel = tabPane.getSelectionModel();
125
126
		int selectIndex = selectionModel.getSelectedIndex() + offset;
127
		if (selectIndex < 0)
128
			selectionModel.selectLast();
129
		else if(selectIndex >= tabPane.getTabs().size())
130
			selectionModel.selectFirst();
131
		else
132
			selectionModel.select(selectIndex);
133114
	}
134115
...
148129
149130
		markdownEditorPane.pathProperty().bind(path);
150
		markdownEditorPane.installEditorShortcuts(mainWindow.getEditorShortcuts());
151
		markdownEditorPane.installEditorShortcuts(EventHandlerHelper
152
			.on(EventPattern.keyPressed(KeyCode.TAB, KeyCombination.CONTROL_DOWN)).act(e -> selectNextPreviousTab(1))
153
			.on(EventPattern.keyPressed(KeyCode.TAB, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)).act(e -> selectNextPreviousTab(-1))
154
			.create());
155131
156132
		load();
...
198174
			markdownEditorPane.getUndoManager().mark();
199175
		} catch (IOException ex) {
200
			Alert alert = mainWindow.createAlert(AlertType.ERROR, "Load",
201
				"Failed to load '%s'.\n\nReason: %s", path, ex.getMessage());
176
			Alert alert = mainWindow.createAlert(AlertType.ERROR,
177
				Messages.get("FileEditor.loadFailed.title"),
178
				Messages.get("FileEditor.loadFailed.message"), path, ex.getMessage());
202179
			alert.showAndWait();
203180
		}
...
223200
			return true;
224201
		} catch (IOException ex) {
225
			Alert alert = mainWindow.createAlert(AlertType.ERROR, "Save",
226
				"Failed to save '%s'.\n\nReason: %s", path.get(), ex.getMessage());
202
			Alert alert = mainWindow.createAlert(AlertType.ERROR,
203
				Messages.get("FileEditor.saveFailed.title"),
204
				Messages.get("FileEditor.saveFailed.message"), path.get(), ex.getMessage());
227205
			alert.showAndWait();
228206
			return false;
M src/main/java/org/markdownwriterfx/FileEditorTabPane.java
140140
141141
	FileEditor[] openEditor() {
142
		FileChooser fileChooser = createFileChooser("Open Markdown File");
142
		FileChooser fileChooser = createFileChooser(Messages.get("FileEditorTabPane.openChooser.title"));
143143
		List<File> selectedFiles = fileChooser.showOpenMultipleDialog(mainWindow.getScene().getWindow());
144144
		if (selectedFiles == null)
...
154154
			FileEditor fileEditor = (FileEditor) tabPane.getTabs().get(0).getUserData();
155155
			if (fileEditor.getPath() == null && !fileEditor.isModified())
156
				closeEditor(fileEditor);
156
				closeEditor(fileEditor, false);
157157
		}
158158
...
185185
			tabPane.getSelectionModel().select(fileEditor.getTab());
186186
187
			FileChooser fileChooser = createFileChooser("Save Markdown File");
187
			FileChooser fileChooser = createFileChooser(Messages.get("FileEditorTabPane.saveChooser.title"));
188188
			File file = fileChooser.showSaveDialog(mainWindow.getScene().getWindow());
189189
			if (file == null)
...
213213
			return true;
214214
215
		Alert alert = mainWindow.createAlert(AlertType.CONFIRMATION, "Close",
216
			"'%s' has been modified. Save changes?", fileEditor.getTab().getText());
215
		Alert alert = mainWindow.createAlert(AlertType.CONFIRMATION,
216
			Messages.get("FileEditorTabPane.closeAlert.title"),
217
			Messages.get("FileEditorTabPane.closeAlert.message"), fileEditor.getTab().getText());
217218
		alert.getButtonTypes().setAll(ButtonType.YES, ButtonType.NO, ButtonType.CANCEL);
218219
219220
		ButtonType result = alert.showAndWait().get();
220221
		if (result != ButtonType.YES)
221222
			return (result == ButtonType.NO);
222223
223224
		return saveEditor(fileEditor);
224225
	}
225226
226
	boolean closeEditor(FileEditor fileEditor) {
227
	boolean closeEditor(FileEditor fileEditor, boolean save) {
227228
		if (fileEditor == null)
228229
			return true;
229230
230231
		Tab tab = fileEditor.getTab();
231232
232
		Event event = new Event(tab,tab,Tab.TAB_CLOSE_REQUEST_EVENT);
233
		Event.fireEvent(tab, event);
234
		if (event.isConsumed())
235
			return false;
233
		if (save) {
234
			Event event = new Event(tab,tab,Tab.TAB_CLOSE_REQUEST_EVENT);
235
			Event.fireEvent(tab, event);
236
			if (event.isConsumed())
237
				return false;
238
		}
236239
237240
		tabPane.getTabs().remove(tab);
...
246249
		FileEditor activeEditor = activeFileEditor.get();
247250
248
		// try to close active tab first because in case user decides to cancel,
249
		// then the other tabs stay open
250
		if (activeEditor != null && !closeEditor(activeEditor))
251
		// try to save active tab first because in case the user decides to cancel,
252
		// then it stays active
253
		if (activeEditor != null && !canCloseEditor(activeEditor))
251254
			return false;
252
253
		// select first tab
254
		if (!tabPane.getTabs().isEmpty())
255
			tabPane.getSelectionModel().select(0);
256255
257
		// try to close all tabs
258
		for (FileEditor fileEditor : allEditors) {
256
		// save modified tabs
257
		for (int i = 0; i < allEditors.length; i++) {
258
			FileEditor fileEditor = allEditors[i];
259259
			if (fileEditor == activeEditor)
260260
				continue;
261261
262
			if (!closeEditor(fileEditor))
262
			if (fileEditor.isModified()) {
263
				// activate the modified tab to make its modified content visible to the user
264
				tabPane.getSelectionModel().select(i);
265
266
				if (!canCloseEditor(fileEditor))
267
					return false;
268
			}
269
		}
270
271
		// close all tabs
272
		for (FileEditor fileEditor : allEditors) {
273
			if (!closeEditor(fileEditor, false))
263274
				return false;
264275
		}
...
290301
		fileChooser.setTitle(title);
291302
		fileChooser.getExtensionFilters().addAll(
292
				new ExtensionFilter("Markdown Files", "*.md", "*.markdown", "*.txt"),
293
				new ExtensionFilter("All Files", "*.*"));
303
			new ExtensionFilter(Messages.get("FileEditorTabPane.chooser.markdownFilesFilter"), "*.md", "*.markdown", "*.txt"),
304
			new ExtensionFilter(Messages.get("FileEditorTabPane.chooser.allFilesFilter"), "*.*"));
294305
295306
		String lastDirectory = MarkdownWriterFXApp.getState().get("lastDirectory", null);
M src/main/java/org/markdownwriterfx/MainWindow.java
2828
package org.markdownwriterfx;
2929
30
import javafx.beans.binding.Bindings;
31
import javafx.beans.binding.BooleanBinding;
32
import javafx.beans.property.BooleanProperty;
33
import javafx.beans.property.SimpleBooleanProperty;
34
import javafx.beans.value.ObservableBooleanValue;
35
import javafx.event.Event;
36
import javafx.event.EventHandler;
37
import javafx.scene.Node;
38
import javafx.scene.Scene;
39
import javafx.scene.control.Alert;
40
import javafx.scene.control.Alert.AlertType;
41
import javafx.scene.image.Image;
42
import javafx.scene.image.ImageView;
43
import javafx.scene.control.Menu;
44
import javafx.scene.control.MenuBar;
45
import javafx.scene.control.MenuItem;
46
import javafx.scene.control.ToolBar;
47
import javafx.scene.input.KeyCode;
48
import javafx.scene.input.KeyCombination;
49
import javafx.scene.input.KeyEvent;
50
import javafx.scene.layout.BorderPane;
51
import javafx.scene.layout.VBox;
52
import javafx.stage.Window;
53
import javafx.stage.WindowEvent;
54
import org.fxmisc.wellbehaved.event.EventHandlerHelper;
55
import org.fxmisc.wellbehaved.event.EventPattern;
56
import org.markdownwriterfx.editor.MarkdownEditorPane;
57
import org.markdownwriterfx.options.OptionsDialog;
58
import org.markdownwriterfx.util.Action;
59
import org.markdownwriterfx.util.ActionUtils;
60
import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.*;
61
import java.util.function.Consumer;
62
import java.util.function.Function;
63
64
/**
65
 * Main window containing a tab pane in the center for file editors.
66
 *
67
 * @author Karl Tauber
68
 */
69
class MainWindow
70
{
71
	private final Scene scene;
72
	private final FileEditorTabPane fileEditorTabPane;
73
	private MenuBar menuBar;
74
75
	MainWindow() {
76
		fileEditorTabPane = new FileEditorTabPane(this);
77
78
		BorderPane borderPane = new BorderPane();
79
		borderPane.setPrefSize(800, 800);
80
		borderPane.setTop(createMenuBarAndToolBar());
81
		borderPane.setCenter(fileEditorTabPane.getNode());
82
83
		scene = new Scene(borderPane);
84
		scene.getStylesheets().add("org/markdownwriterfx/MarkdownWriter.css");
85
		scene.windowProperty().addListener((observable, oldWindow, newWindow) -> {
86
			newWindow.setOnCloseRequest(e -> {
87
				if (!fileEditorTabPane.closeAllEditors())
88
					e.consume();
89
			});
90
91
			// workaround for a bug in JavaFX: unselect menubar if window looses focus
92
			newWindow.focusedProperty().addListener((obs, oldFocused, newFocused) -> {
93
				if (!newFocused) {
94
					// send an ESC key event to the menubar
95
					menuBar.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED,
96
							KeyEvent.CHAR_UNDEFINED, "", KeyCode.ESCAPE,
97
							false, false, false, false));
98
				}
99
			});
100
		});
101
	}
102
103
	Scene getScene() {
104
		return scene;
105
	}
106
107
	private Node createMenuBarAndToolBar() {
108
		BooleanBinding activeFileEditorIsNull = fileEditorTabPane.activeFileEditorProperty().isNull();
109
110
		// File actions
111
		Action fileNewAction = new Action("New", "Shortcut+N", FILE_ALT, e -> fileNew());
112
		Action fileOpenAction = new Action("Open...", "Shortcut+O", FOLDER_OPEN_ALT, e -> fileOpen());
113
		Action fileCloseAction = new Action("Close", "Shortcut+W", null, e -> fileClose(), activeFileEditorIsNull);
114
		Action fileCloseAllAction = new Action("Close All", null, null, e -> fileCloseAll(), activeFileEditorIsNull);
115
		Action fileSaveAction = new Action("Save", "Shortcut+S", FLOPPY_ALT, e -> fileSave(),
116
				createActiveBooleanProperty(FileEditor::modifiedProperty).not());
117
		Action fileSaveAllAction = new Action("Save All", "Shortcut+Shift+S", null, e -> fileSaveAll(),
118
				Bindings.not(fileEditorTabPane.anyFileEditorModifiedProperty()));
119
		Action fileExitAction = new Action("Exit", null, null, e -> fileExit());
120
121
		// Edit actions
122
		Action editUndoAction = new Action("Undo", "Shortcut+Z", UNDO,
123
				e -> getActiveEditor().undo(),
124
				createActiveBooleanProperty(FileEditor::canUndoProperty).not());
125
		Action editRedoAction = new Action("Redo", "Shortcut+Y", REPEAT,
126
				e -> getActiveEditor().redo(),
127
				createActiveBooleanProperty(FileEditor::canRedoProperty).not());
128
129
		// Insert actions
130
		Action insertBoldAction = new Action("Bold", "Shortcut+B", BOLD,
131
				e -> getActiveEditor().surroundSelection("**", "**"),
132
				activeFileEditorIsNull);
133
		Action insertItalicAction = new Action("Italic", "Shortcut+I", ITALIC,
134
				e -> getActiveEditor().surroundSelection("*", "*"),
135
				activeFileEditorIsNull);
136
		Action insertStrikethroughAction = new Action("Strikethrough", "Shortcut+T", STRIKETHROUGH,
137
				e -> getActiveEditor().surroundSelection("~~", "~~"),
138
				activeFileEditorIsNull);
139
		Action insertBlockquoteAction = new Action("Blockquote", "Ctrl+Q", QUOTE_LEFT, // not Shortcut+Q because of conflict on Mac
140
				e -> getActiveEditor().surroundSelection("\n\n> ", ""),
141
				activeFileEditorIsNull);
142
		Action insertCodeAction = new Action("Inline Code", "Shortcut+K", CODE,
143
				e -> getActiveEditor().surroundSelection("`", "`"),
144
				activeFileEditorIsNull);
145
		Action insertFencedCodeBlockAction = new Action("Fenced Code Block", "Shortcut+Shift+K", FILE_CODE_ALT,
146
				e -> getActiveEditor().surroundSelection("\n\n```\n", "\n```\n\n", "enter code here"),
147
				activeFileEditorIsNull);
148
149
		Action insertLinkAction = new Action("Link...", "Shortcut+L", LINK,
150
				e -> getActiveEditor().insertLink(),
151
				activeFileEditorIsNull);
152
		Action insertImageAction = new Action("Image...", "Shortcut+G", PICTURE_ALT,
153
				e -> getActiveEditor().insertImage(),
154
				activeFileEditorIsNull);
155
156
		Action insertHeader1Action = new Action("Header 1", "Shortcut+1", HEADER,
157
				e -> getActiveEditor().surroundSelection("\n\n# ", "", "header 1"),
158
				activeFileEditorIsNull);
159
		Action insertHeader2Action = new Action("Header 2", "Shortcut+2", HEADER,
160
				e -> getActiveEditor().surroundSelection("\n\n## ", "", "header 2"),
161
				activeFileEditorIsNull);
162
		Action insertHeader3Action = new Action("Header 3", "Shortcut+3", HEADER,
163
				e -> getActiveEditor().surroundSelection("\n\n### ", "", "header 3"),
164
				activeFileEditorIsNull);
165
		Action insertHeader4Action = new Action("Header 4", "Shortcut+4", HEADER,
166
				e -> getActiveEditor().surroundSelection("\n\n#### ", "", "header 4"),
167
				activeFileEditorIsNull);
168
		Action insertHeader5Action = new Action("Header 5", "Shortcut+5", HEADER,
169
				e -> getActiveEditor().surroundSelection("\n\n##### ", "", "header 5"),
170
				activeFileEditorIsNull);
171
		Action insertHeader6Action = new Action("Header 6", "Shortcut+6", HEADER,
172
				e -> getActiveEditor().surroundSelection("\n\n###### ", "", "header 6"),
173
				activeFileEditorIsNull);
174
175
		Action insertUnorderedListAction = new Action("Unordered List", "Shortcut+U", LIST_UL,
176
				e -> getActiveEditor().surroundSelection("\n\n* ", ""),
177
				activeFileEditorIsNull);
178
		Action insertOrderedListAction = new Action("Ordered List", "Shortcut+Shift+O", LIST_OL,
179
				e -> getActiveEditor().surroundSelection("\n\n1. ", ""),
180
				activeFileEditorIsNull);
181
		Action insertHorizontalRuleAction = new Action("Horizontal Rule", "Shortcut+H", null,
182
				e -> getActiveEditor().surroundSelection("\n\n---\n\n", ""),
183
				activeFileEditorIsNull);
184
185
		// Tools actions
186
		Action toolsOptionsAction = new Action("Options", "Shortcut+,", null, e -> toolsOptions());
187
188
		// Help actions
189
		Action helpAboutAction = new Action("About Markdown Writer FX", null, null, e -> helpAbout());
190
191
192
		//---- MenuBar ----
193
194
		Menu fileMenu = ActionUtils.createMenu("File",
195
				fileNewAction,
196
				fileOpenAction,
197
				null,
198
				fileCloseAction,
199
				fileCloseAllAction,
200
				null,
201
				fileSaveAction,
202
				fileSaveAllAction,
203
				null,
204
				fileExitAction);
205
206
		Menu editMenu = ActionUtils.createMenu("Edit",
207
				editUndoAction,
208
				editRedoAction);
209
210
		Menu insertMenu = ActionUtils.createMenu("Insert",
211
				insertBoldAction,
212
				insertItalicAction,
213
				insertStrikethroughAction,
214
				insertBlockquoteAction,
215
				insertCodeAction,
216
				insertFencedCodeBlockAction,
217
				null,
218
				insertLinkAction,
219
				insertImageAction,
220
				null,
221
				insertHeader1Action,
222
				insertHeader2Action,
223
				insertHeader3Action,
224
				insertHeader4Action,
225
				insertHeader5Action,
226
				insertHeader6Action,
227
				null,
228
				insertUnorderedListAction,
229
				insertOrderedListAction,
230
				insertHorizontalRuleAction);
231
232
		Menu toolsMenu = ActionUtils.createMenu("Tools",
233
				toolsOptionsAction);
234
235
		Menu helpMenu = ActionUtils.createMenu("Help",
236
				helpAboutAction);
237
238
		menuBar = new MenuBar(fileMenu, editMenu, insertMenu, toolsMenu, helpMenu);
239
240
241
		//---- ToolBar ----
242
243
		ToolBar toolBar = ActionUtils.createToolBar(
244
				fileNewAction,
245
				fileOpenAction,
246
				fileSaveAction,
247
				null,
248
				editUndoAction,
249
				editRedoAction,
250
				null,
251
				insertBoldAction,
252
				insertItalicAction,
253
				insertBlockquoteAction,
254
				insertCodeAction,
255
				insertFencedCodeBlockAction,
256
				null,
257
				insertLinkAction,
258
				insertImageAction,
259
				null,
260
				insertHeader1Action,
261
				null,
262
				insertUnorderedListAction,
263
				insertOrderedListAction);
264
265
		return new VBox(menuBar, toolBar);
266
	}
267
268
	private MarkdownEditorPane getActiveEditor() {
269
		return fileEditorTabPane.getActiveFileEditor().getEditor();
270
	}
271
272
	/**
273
	 * Creates a boolean property that is bound to another boolean value
274
	 * of the active editor.
275
	 */
276
	private BooleanProperty createActiveBooleanProperty(Function<FileEditor, ObservableBooleanValue> func) {
277
		BooleanProperty b = new SimpleBooleanProperty();
278
		FileEditor fileEditor = fileEditorTabPane.getActiveFileEditor();
279
		if (fileEditor != null)
280
			b.bind(func.apply(fileEditor));
281
		fileEditorTabPane.activeFileEditorProperty().addListener((observable, oldFileEditor, newFileEditor) -> {
282
			b.unbind();
283
			if (newFileEditor != null)
284
				b.bind(func.apply(newFileEditor));
285
			else
286
				b.set(false);
287
		});
288
		return b;
289
	}
290
291
	Alert createAlert(AlertType alertType, String title,
292
		String contentTextFormat, Object... contentTextArgs)
293
	{
294
		Alert alert = new Alert(alertType);
295
		alert.setTitle(title);
296
		alert.setHeaderText(null);
297
		alert.setContentText(String.format(contentTextFormat, contentTextArgs));
298
		alert.initOwner(getScene().getWindow());
299
		return alert;
300
	}
301
302
	/**
303
	 * When the editor control (RichTextFX) is focused, it consumes all key events
304
	 * and the menu accelerators do not work. Looks like a bug to me...
305
	 * Workaround: install keyboard shortcuts into the editor component.
306
	 */
307
	private EventHandler<KeyEvent> editorShortcuts;
308
	EventHandler<KeyEvent> getEditorShortcuts() {
309
		if (editorShortcuts != null)
310
			return editorShortcuts;
311
312
		EventHandlerHelper.Builder<KeyEvent> builder = null;
313
		for (Menu menu : menuBar.getMenus()) {
314
			for (MenuItem menuItem : menu.getItems()) {
315
				KeyCombination accelerator = menuItem.getAccelerator();
316
				if (accelerator != null) {
317
					Consumer<? super KeyEvent> action = e -> menuItem.getOnAction().handle(null);
318
					if (builder != null)
319
						builder = builder.on(EventPattern.keyPressed(accelerator)).act(action);
320
					else
321
						builder = EventHandlerHelper.on(EventPattern.keyPressed(accelerator)).act(action);
322
				}
323
			}
324
		}
325
		editorShortcuts = builder.create();
326
		return editorShortcuts;
327
	}
328
329
	//---- File actions -------------------------------------------------------
330
331
	private void fileNew() {
332
		fileEditorTabPane.newEditor();
333
	}
334
335
	private void fileOpen() {
336
		fileEditorTabPane.openEditor();
337
	}
338
339
	private void fileClose() {
340
		fileEditorTabPane.closeEditor(fileEditorTabPane.getActiveFileEditor());
341
	}
342
343
	private void fileCloseAll() {
344
		fileEditorTabPane.closeAllEditors();
345
	}
346
347
	private void fileSave() {
348
		fileEditorTabPane.saveEditor(fileEditorTabPane.getActiveFileEditor());
349
	}
350
351
	private void fileSaveAll() {
352
		fileEditorTabPane.saveAllEditors();
353
	}
354
355
	private void fileExit() {
356
		Window window = scene.getWindow();
357
		Event.fireEvent(window, new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
358
	}
359
360
	//---- Tools actions ------------------------------------------------------
361
362
	private void toolsOptions() {
363
		OptionsDialog dialog = new OptionsDialog(getScene().getWindow());
364
		dialog.showAndWait();
365
	}
366
367
	//---- Help actions -------------------------------------------------------
368
369
	private void helpAbout() {
370
		Alert alert = new Alert(AlertType.INFORMATION);
371
		alert.setTitle("About");
372
		alert.setHeaderText("Markdown Writer FX");
373
		alert.setContentText("Copyright (c) 2015 Karl Tauber <karl at jformdesigner dot com>\nAll rights reserved.");
30
import java.text.MessageFormat;
31
import java.util.function.Function;
32
import javafx.beans.binding.Bindings;
33
import javafx.beans.binding.BooleanBinding;
34
import javafx.beans.property.BooleanProperty;
35
import javafx.beans.property.SimpleBooleanProperty;
36
import javafx.beans.value.ObservableBooleanValue;
37
import javafx.event.Event;
38
import javafx.scene.Node;
39
import javafx.scene.Scene;
40
import javafx.scene.control.Alert;
41
import javafx.scene.control.Alert.AlertType;
42
import javafx.scene.image.Image;
43
import javafx.scene.image.ImageView;
44
import javafx.scene.control.Menu;
45
import javafx.scene.control.MenuBar;
46
import javafx.scene.control.ToolBar;
47
import javafx.scene.input.KeyCode;
48
import javafx.scene.input.KeyEvent;
49
import javafx.scene.layout.BorderPane;
50
import javafx.scene.layout.VBox;
51
import javafx.stage.Window;
52
import javafx.stage.WindowEvent;
53
import org.markdownwriterfx.editor.MarkdownEditorPane;
54
import org.markdownwriterfx.options.OptionsDialog;
55
import org.markdownwriterfx.util.Action;
56
import org.markdownwriterfx.util.ActionUtils;
57
import static de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon.*;
58
59
/**
60
 * Main window containing a tab pane in the center for file editors.
61
 *
62
 * @author Karl Tauber
63
 */
64
class MainWindow
65
{
66
	private final Scene scene;
67
	private final FileEditorTabPane fileEditorTabPane;
68
	private MenuBar menuBar;
69
70
	MainWindow() {
71
		fileEditorTabPane = new FileEditorTabPane(this);
72
73
		BorderPane borderPane = new BorderPane();
74
		borderPane.setPrefSize(800, 800);
75
		borderPane.setTop(createMenuBarAndToolBar());
76
		borderPane.setCenter(fileEditorTabPane.getNode());
77
78
		scene = new Scene(borderPane);
79
		scene.getStylesheets().add("org/markdownwriterfx/MarkdownWriter.css");
80
		scene.windowProperty().addListener((observable, oldWindow, newWindow) -> {
81
			newWindow.setOnCloseRequest(e -> {
82
				if (!fileEditorTabPane.closeAllEditors())
83
					e.consume();
84
			});
85
86
			// workaround for a bug in JavaFX: unselect menubar if window looses focus
87
			newWindow.focusedProperty().addListener((obs, oldFocused, newFocused) -> {
88
				if (!newFocused) {
89
					// send an ESC key event to the menubar
90
					menuBar.fireEvent(new KeyEvent(KeyEvent.KEY_PRESSED,
91
							KeyEvent.CHAR_UNDEFINED, "", KeyCode.ESCAPE,
92
							false, false, false, false));
93
				}
94
			});
95
		});
96
	}
97
98
	Scene getScene() {
99
		return scene;
100
	}
101
102
	private Node createMenuBarAndToolBar() {
103
		BooleanBinding activeFileEditorIsNull = fileEditorTabPane.activeFileEditorProperty().isNull();
104
105
		// File actions
106
		Action fileNewAction = new Action(Messages.get("MainWindow.fileNewAction"), "Shortcut+N", FILE_ALT, e -> fileNew());
107
		Action fileOpenAction = new Action(Messages.get("MainWindow.fileOpenAction"), "Shortcut+O", FOLDER_OPEN_ALT, e -> fileOpen());
108
		Action fileCloseAction = new Action(Messages.get("MainWindow.fileCloseAction"), "Shortcut+W", null, e -> fileClose(), activeFileEditorIsNull);
109
		Action fileCloseAllAction = new Action(Messages.get("MainWindow.fileCloseAllAction"), null, null, e -> fileCloseAll(), activeFileEditorIsNull);
110
		Action fileSaveAction = new Action(Messages.get("MainWindow.fileSaveAction"), "Shortcut+S", FLOPPY_ALT, e -> fileSave(),
111
				createActiveBooleanProperty(FileEditor::modifiedProperty).not());
112
		Action fileSaveAllAction = new Action(Messages.get("MainWindow.fileSaveAllAction"), "Shortcut+Shift+S", null, e -> fileSaveAll(),
113
				Bindings.not(fileEditorTabPane.anyFileEditorModifiedProperty()));
114
		Action fileExitAction = new Action(Messages.get("MainWindow.fileExitAction"), null, null, e -> fileExit());
115
116
		// Edit actions
117
		Action editUndoAction = new Action(Messages.get("MainWindow.editUndoAction"), "Shortcut+Z", UNDO,
118
				e -> getActiveEditor().undo(),
119
				createActiveBooleanProperty(FileEditor::canUndoProperty).not());
120
		Action editRedoAction = new Action(Messages.get("MainWindow.editRedoAction"), "Shortcut+Y", REPEAT,
121
				e -> getActiveEditor().redo(),
122
				createActiveBooleanProperty(FileEditor::canRedoProperty).not());
123
124
		// Insert actions
125
		Action insertBoldAction = new Action(Messages.get("MainWindow.insertBoldAction"), "Shortcut+B", BOLD,
126
				e -> getActiveEditor().surroundSelection("**", "**"),
127
				activeFileEditorIsNull);
128
		Action insertItalicAction = new Action(Messages.get("MainWindow.insertItalicAction"), "Shortcut+I", ITALIC,
129
				e -> getActiveEditor().surroundSelection("*", "*"),
130
				activeFileEditorIsNull);
131
		Action insertStrikethroughAction = new Action(Messages.get("MainWindow.insertStrikethroughAction"), "Shortcut+T", STRIKETHROUGH,
132
				e -> getActiveEditor().surroundSelection("~~", "~~"),
133
				activeFileEditorIsNull);
134
		Action insertBlockquoteAction = new Action(Messages.get("MainWindow.insertBlockquoteAction"), "Ctrl+Q", QUOTE_LEFT, // not Shortcut+Q because of conflict on Mac
135
				e -> getActiveEditor().surroundSelection("\n\n> ", ""),
136
				activeFileEditorIsNull);
137
		Action insertCodeAction = new Action(Messages.get("MainWindow.insertCodeAction"), "Shortcut+K", CODE,
138
				e -> getActiveEditor().surroundSelection("`", "`"),
139
				activeFileEditorIsNull);
140
		Action insertFencedCodeBlockAction = new Action(Messages.get("MainWindow.insertFencedCodeBlockAction"), "Shortcut+Shift+K", FILE_CODE_ALT,
141
				e -> getActiveEditor().surroundSelection("\n\n```\n", "\n```\n\n", Messages.get("MainWindow.insertFencedCodeBlockText")),
142
				activeFileEditorIsNull);
143
144
		Action insertLinkAction = new Action(Messages.get("MainWindow.insertLinkAction"), "Shortcut+L", LINK,
145
				e -> getActiveEditor().insertLink(),
146
				activeFileEditorIsNull);
147
		Action insertImageAction = new Action(Messages.get("MainWindow.insertImageAction"), "Shortcut+G", PICTURE_ALT,
148
				e -> getActiveEditor().insertImage(),
149
				activeFileEditorIsNull);
150
151
		Action insertHeader1Action = new Action(Messages.get("MainWindow.insertHeader1Action"), "Shortcut+1", HEADER,
152
				e -> getActiveEditor().surroundSelection("\n\n# ", "", Messages.get("MainWindow.insertHeader1Text")),
153
				activeFileEditorIsNull);
154
		Action insertHeader2Action = new Action(Messages.get("MainWindow.insertHeader2Action"), "Shortcut+2", HEADER,
155
				e -> getActiveEditor().surroundSelection("\n\n## ", "", Messages.get("MainWindow.insertHeader2Text")),
156
				activeFileEditorIsNull);
157
		Action insertHeader3Action = new Action(Messages.get("MainWindow.insertHeader3Action"), "Shortcut+3", HEADER,
158
				e -> getActiveEditor().surroundSelection("\n\n### ", "", Messages.get("MainWindow.insertHeader3Text")),
159
				activeFileEditorIsNull);
160
		Action insertHeader4Action = new Action(Messages.get("MainWindow.insertHeader4Action"), "Shortcut+4", HEADER,
161
				e -> getActiveEditor().surroundSelection("\n\n#### ", "", Messages.get("MainWindow.insertHeader4Text")),
162
				activeFileEditorIsNull);
163
		Action insertHeader5Action = new Action(Messages.get("MainWindow.insertHeader5Action"), "Shortcut+5", HEADER,
164
				e -> getActiveEditor().surroundSelection("\n\n##### ", "", Messages.get("MainWindow.insertHeader5Text")),
165
				activeFileEditorIsNull);
166
		Action insertHeader6Action = new Action(Messages.get("MainWindow.insertHeader6Action"), "Shortcut+6", HEADER,
167
				e -> getActiveEditor().surroundSelection("\n\n###### ", "", Messages.get("MainWindow.insertHeader6Text")),
168
				activeFileEditorIsNull);
169
170
		Action insertUnorderedListAction = new Action(Messages.get("MainWindow.insertUnorderedListAction"), "Shortcut+U", LIST_UL,
171
				e -> getActiveEditor().surroundSelection("\n\n* ", ""),
172
				activeFileEditorIsNull);
173
		Action insertOrderedListAction = new Action(Messages.get("MainWindow.insertOrderedListAction"), "Shortcut+Shift+O", LIST_OL,
174
				e -> getActiveEditor().surroundSelection("\n\n1. ", ""),
175
				activeFileEditorIsNull);
176
		Action insertHorizontalRuleAction = new Action(Messages.get("MainWindow.insertHorizontalRuleAction"), "Shortcut+H", null,
177
				e -> getActiveEditor().surroundSelection("\n\n---\n\n", ""),
178
				activeFileEditorIsNull);
179
180
		// Tools actions
181
		Action toolsOptionsAction = new Action(Messages.get("MainWindow.toolsOptionsAction"), "Shortcut+,", null, e -> toolsOptions());
182
183
		// Help actions
184
		Action helpAboutAction = new Action(Messages.get("MainWindow.helpAboutAction"), null, null, e -> helpAbout());
185
186
187
		//---- MenuBar ----
188
189
		Menu fileMenu = ActionUtils.createMenu(Messages.get("MainWindow.fileMenu"),
190
				fileNewAction,
191
				fileOpenAction,
192
				null,
193
				fileCloseAction,
194
				fileCloseAllAction,
195
				null,
196
				fileSaveAction,
197
				fileSaveAllAction,
198
				null,
199
				fileExitAction);
200
201
		Menu editMenu = ActionUtils.createMenu(Messages.get("MainWindow.editMenu"),
202
				editUndoAction,
203
				editRedoAction);
204
205
		Menu insertMenu = ActionUtils.createMenu(Messages.get("MainWindow.insertMenu"),
206
				insertBoldAction,
207
				insertItalicAction,
208
				insertStrikethroughAction,
209
				insertBlockquoteAction,
210
				insertCodeAction,
211
				insertFencedCodeBlockAction,
212
				null,
213
				insertLinkAction,
214
				insertImageAction,
215
				null,
216
				insertHeader1Action,
217
				insertHeader2Action,
218
				insertHeader3Action,
219
				insertHeader4Action,
220
				insertHeader5Action,
221
				insertHeader6Action,
222
				null,
223
				insertUnorderedListAction,
224
				insertOrderedListAction,
225
				insertHorizontalRuleAction);
226
227
		Menu toolsMenu = ActionUtils.createMenu(Messages.get("MainWindow.toolsMenu"),
228
				toolsOptionsAction);
229
230
		Menu helpMenu = ActionUtils.createMenu(Messages.get("MainWindow.helpMenu"),
231
				helpAboutAction);
232
233
		menuBar = new MenuBar(fileMenu, editMenu, insertMenu, toolsMenu, helpMenu);
234
235
236
		//---- ToolBar ----
237
238
		ToolBar toolBar = ActionUtils.createToolBar(
239
				fileNewAction,
240
				fileOpenAction,
241
				fileSaveAction,
242
				null,
243
				editUndoAction,
244
				editRedoAction,
245
				null,
246
				insertBoldAction,
247
				insertItalicAction,
248
				insertBlockquoteAction,
249
				insertCodeAction,
250
				insertFencedCodeBlockAction,
251
				null,
252
				insertLinkAction,
253
				insertImageAction,
254
				null,
255
				insertHeader1Action,
256
				null,
257
				insertUnorderedListAction,
258
				insertOrderedListAction);
259
260
		return new VBox(menuBar, toolBar);
261
	}
262
263
	private MarkdownEditorPane getActiveEditor() {
264
		return fileEditorTabPane.getActiveFileEditor().getEditor();
265
	}
266
267
	/**
268
	 * Creates a boolean property that is bound to another boolean value
269
	 * of the active editor.
270
	 */
271
	private BooleanProperty createActiveBooleanProperty(Function<FileEditor, ObservableBooleanValue> func) {
272
		BooleanProperty b = new SimpleBooleanProperty();
273
		FileEditor fileEditor = fileEditorTabPane.getActiveFileEditor();
274
		if (fileEditor != null)
275
			b.bind(func.apply(fileEditor));
276
		fileEditorTabPane.activeFileEditorProperty().addListener((observable, oldFileEditor, newFileEditor) -> {
277
			b.unbind();
278
			if (newFileEditor != null)
279
				b.bind(func.apply(newFileEditor));
280
			else
281
				b.set(false);
282
		});
283
		return b;
284
	}
285
286
	Alert createAlert(AlertType alertType, String title,
287
		String contentTextFormat, Object... contentTextArgs)
288
	{
289
		Alert alert = new Alert(alertType);
290
		alert.setTitle(title);
291
		alert.setHeaderText(null);
292
		alert.setContentText(MessageFormat.format(contentTextFormat, contentTextArgs));
293
		alert.initOwner(getScene().getWindow());
294
		return alert;
295
	}
296
297
	//---- File actions -------------------------------------------------------
298
299
	private void fileNew() {
300
		fileEditorTabPane.newEditor();
301
	}
302
303
	private void fileOpen() {
304
		fileEditorTabPane.openEditor();
305
	}
306
307
	private void fileClose() {
308
		fileEditorTabPane.closeEditor(fileEditorTabPane.getActiveFileEditor(), true);
309
	}
310
311
	private void fileCloseAll() {
312
		fileEditorTabPane.closeAllEditors();
313
	}
314
315
	private void fileSave() {
316
		fileEditorTabPane.saveEditor(fileEditorTabPane.getActiveFileEditor());
317
	}
318
319
	private void fileSaveAll() {
320
		fileEditorTabPane.saveAllEditors();
321
	}
322
323
	private void fileExit() {
324
		Window window = scene.getWindow();
325
		Event.fireEvent(window, new WindowEvent(window, WindowEvent.WINDOW_CLOSE_REQUEST));
326
	}
327
328
	//---- Tools actions ------------------------------------------------------
329
330
	private void toolsOptions() {
331
		OptionsDialog dialog = new OptionsDialog(getScene().getWindow());
332
		dialog.showAndWait();
333
	}
334
335
	//---- Help actions -------------------------------------------------------
336
337
	private void helpAbout() {
338
		Alert alert = new Alert(AlertType.INFORMATION);
339
		alert.setTitle(Messages.get("MainWindow.about.title"));
340
		alert.setHeaderText(Messages.get("MainWindow.about.headerText"));
341
		alert.setContentText(Messages.get("MainWindow.about.contentText"));
374342
		alert.setGraphic(new ImageView(new Image("org/markdownwriterfx/markdownwriterfx32.png")));
375343
		alert.initOwner(getScene().getWindow());
A src/main/java/org/markdownwriterfx/Messages.java
1
/*
2
 * Copyright (c) 2016 Karl Tauber <karl at jformdesigner dot com>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 *  * Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 *
11
 *  * Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 *
15
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
28
package org.markdownwriterfx;
29
30
import java.text.MessageFormat;
31
import java.util.ResourceBundle;
32
33
/**
34
 * @author Karl Tauber
35
 */
36
public class Messages
37
{
38
	private static final String BUNDLE_NAME = "org.markdownwriterfx.messages";
39
	private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);
40
41
	private Messages() {
42
	}
43
44
	public static String get(String key) {
45
//		try {
46
			return RESOURCE_BUNDLE.getString(key);
47
//		} catch (MissingResourceException e) {
48
//			return '!' + key + '!';
49
//		}
50
	}
51
52
	public static String get(String key, Object... args) {
53
		return MessageFormat.format(get(key), args);
54
	}
55
}
156
M src/main/java/org/markdownwriterfx/controls/BrowseDirectoryButton.java
3232
import javafx.scene.control.Tooltip;
3333
import javafx.stage.DirectoryChooser;
34
import org.markdownwriterfx.Messages;
3435
import de.jensd.fx.glyphs.GlyphsDude;
3536
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
...
4546
	public BrowseDirectoryButton() {
4647
		setGraphic(GlyphsDude.createIcon(FontAwesomeIcon.FOLDER_ALT, "1.2em"));
47
		setTooltip(new Tooltip("Browse for local folder"));
48
		setTooltip(new Tooltip(Messages.get("BrowseDirectoryButton.tooltip")));
4849
	}
4950
5051
	@Override
5152
	protected void browse(ActionEvent e) {
5253
		DirectoryChooser directoryChooser = new DirectoryChooser();
53
		directoryChooser.setTitle("Browse for local folder");
54
		directoryChooser.setTitle(Messages.get("BrowseDirectoryButton.chooser.title"));
5455
		directoryChooser.setInitialDirectory(getInitialDirectory());
5556
		File result = directoryChooser.showDialog(getScene().getWindow());
M src/main/java/org/markdownwriterfx/controls/BrowseFileButton.java
4141
import javafx.stage.FileChooser;
4242
import javafx.stage.FileChooser.ExtensionFilter;
43
import org.markdownwriterfx.Messages;
4344
import de.jensd.fx.glyphs.GlyphsDude;
4445
import de.jensd.fx.glyphs.fontawesome.FontAwesomeIcon;
...
5657
	public BrowseFileButton() {
5758
		setGraphic(GlyphsDude.createIcon(FontAwesomeIcon.FILE_ALT, "1.2em"));
58
		setTooltip(new Tooltip("Browse for local file"));
59
		setTooltip(new Tooltip(Messages.get("BrowseFileButton.tooltip")));
5960
		setOnAction(this::browse);
6061
...
8889
	protected void browse(ActionEvent e) {
8990
		FileChooser fileChooser = new FileChooser();
90
		fileChooser.setTitle("Browse for local file");
91
		fileChooser.setTitle(Messages.get("BrowseFileButton.chooser.title"));
9192
		fileChooser.getExtensionFilters().addAll(extensionFilters);
92
		fileChooser.getExtensionFilters().add(new ExtensionFilter("All Files", "*.*"));
93
		fileChooser.getExtensionFilters().add(new ExtensionFilter(Messages.get("BrowseFileButton.chooser.allFilesFilter"), "*.*"));
9394
		fileChooser.setInitialDirectory(getInitialDirectory());
9495
		File result = fileChooser.showOpenDialog(getScene().getWindow());
M src/main/java/org/markdownwriterfx/dialogs/ImageDialog.java
4040
import javafx.stage.FileChooser.ExtensionFilter;
4141
import javafx.stage.Window;
42
import org.markdownwriterfx.Messages;
4243
import org.markdownwriterfx.controls.BrowseFileButton;
4344
import org.markdownwriterfx.controls.EscapeTextField;
...
5556
5657
	public ImageDialog(Window owner, Path basePath) {
57
		setTitle("Image");
58
		setTitle(Messages.get("ImageDialog.title"));
5859
		initOwner(owner);
5960
		setResizable(true);
6061
6162
		initComponents();
6263
6364
		linkBrowseFileButton.setBasePath(basePath);
64
		linkBrowseFileButton.addExtensionFilter(new ExtensionFilter("Images", "*.png", "*.gif", "*.jpg"));
65
		linkBrowseFileButton.addExtensionFilter(new ExtensionFilter(Messages.get("ImageDialog.chooser.imagesFilter"), "*.png", "*.gif", "*.jpg"));
6566
		linkBrowseFileButton.urlProperty().bindBidirectional(urlField.escapedTextProperty());
6667
...
110111
111112
			//---- urlLabel ----
112
			urlLabel.setText("Image URL:");
113
			urlLabel.setText(Messages.get("ImageDialog.urlLabel.text"));
113114
			pane.add(urlLabel, "cell 0 0");
114115
...
121122
122123
			//---- textLabel ----
123
			textLabel.setText("Alternate Text:");
124
			textLabel.setText(Messages.get("ImageDialog.textLabel.text"));
124125
			pane.add(textLabel, "cell 0 1");
125126
126127
			//---- textField ----
127128
			textField.setEscapeCharacters("[]");
128129
			pane.add(textField, "cell 1 1 2 1");
129130
130131
			//---- titleLabel ----
131
			titleLabel.setText("Title (tooltip):");
132
			titleLabel.setText(Messages.get("ImageDialog.titleLabel.text"));
132133
			pane.add(titleLabel, "cell 0 2");
133134
			pane.add(titleField, "cell 1 2 2 1");
134135
135136
			//---- previewLabel ----
136
			previewLabel.setText("Markdown Preview:");
137
			previewLabel.setText(Messages.get("ImageDialog.previewLabel.text"));
137138
			pane.add(previewLabel, "cell 0 3");
138139
			pane.add(previewField, "cell 1 3 2 1");
M src/main/java/org/markdownwriterfx/dialogs/ImageDialog.jfd
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_51" encoding: "UTF-8"
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_66" encoding: "UTF-8"
22
33
new FormModel {
4
	"i18n.bundlePackage": "org.markdownwriterfx"
5
	"i18n.bundleName": "messages"
6
	"i18n.autoExternalize": true
7
	"i18n.keyPrefix": "ImageDialog"
48
	contentType: "form/javafx"
59
	root: new FormRoot {
...
1216
			add( new FormComponent( "javafx.scene.control.Label" ) {
1317
				name: "urlLabel"
14
				"text": "Image URL:"
18
				"text": new FormMessage( null, "ImageDialog.urlLabel.text" )
1519
				auxiliary() {
1620
					"JavaCodeGenerator.variableLocal": true
...
3438
			add( new FormComponent( "javafx.scene.control.Label" ) {
3539
				name: "textLabel"
36
				"text": "Alternate Text:"
40
				"text": new FormMessage( null, "ImageDialog.textLabel.text" )
3741
				auxiliary() {
3842
					"JavaCodeGenerator.variableLocal": true
...
4953
			add( new FormComponent( "javafx.scene.control.Label" ) {
5054
				name: "titleLabel"
51
				"text": "Title (tooltip):"
55
				"text": new FormMessage( null, "ImageDialog.titleLabel.text" )
5256
				auxiliary() {
5357
					"JavaCodeGenerator.variableLocal": true
...
6367
			add( new FormComponent( "javafx.scene.control.Label" ) {
6468
				name: "previewLabel"
65
				"text": "Markdown Preview:"
69
				"text": new FormMessage( null, "ImageDialog.previewLabel.text" )
6670
				auxiliary() {
6771
					"JavaCodeGenerator.variableLocal": true
M src/main/java/org/markdownwriterfx/dialogs/LinkDialog.java
3939
import javafx.scene.control.Label;
4040
import javafx.stage.Window;
41
import org.markdownwriterfx.Messages;
4142
import org.markdownwriterfx.controls.BrowseDirectoryButton;
4243
import org.markdownwriterfx.controls.BrowseFileButton;
...
5556
5657
	public LinkDialog(Window owner, Path basePath) {
57
		setTitle("Link");
58
		setTitle(Messages.get("LinkDialog.title"));
5859
		initOwner(owner);
5960
		setResizable(true);
...
114115
115116
			//---- urlLabel ----
116
			urlLabel.setText("Link URL:");
117
			urlLabel.setText(Messages.get("LinkDialog.urlLabel.text"));
117118
			pane.add(urlLabel, "cell 0 0");
118119
...
126127
127128
			//---- textLabel ----
128
			textLabel.setText("Link Text:");
129
			textLabel.setText(Messages.get("LinkDialog.textLabel.text"));
129130
			pane.add(textLabel, "cell 0 1");
130131
131132
			//---- textField ----
132133
			textField.setEscapeCharacters("[]");
133134
			pane.add(textField, "cell 1 1 3 1");
134135
135136
			//---- titleLabel ----
136
			titleLabel.setText("Title (tooltip):");
137
			titleLabel.setText(Messages.get("LinkDialog.titleLabel.text"));
137138
			pane.add(titleLabel, "cell 0 2");
138139
			pane.add(titleField, "cell 1 2 3 1");
139140
140141
			//---- previewLabel ----
141
			previewLabel.setText("Markdown Preview:");
142
			previewLabel.setText(Messages.get("LinkDialog.previewLabel.text"));
142143
			pane.add(previewLabel, "cell 0 3");
143144
			pane.add(previewField, "cell 1 3 3 1");
M src/main/java/org/markdownwriterfx/dialogs/LinkDialog.jfd
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_51" encoding: "UTF-8"
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_66" encoding: "UTF-8"
22
33
new FormModel {
4
	"i18n.bundlePackage": "org.markdownwriterfx"
5
	"i18n.bundleName": "messages"
6
	"i18n.autoExternalize": true
7
	"i18n.keyPrefix": "LinkDialog"
48
	contentType: "form/javafx"
59
	root: new FormRoot {
...
1216
			add( new FormComponent( "javafx.scene.control.Label" ) {
1317
				name: "urlLabel"
14
				"text": "Link URL:"
18
				"text": new FormMessage( null, "LinkDialog.urlLabel.text" )
1519
				auxiliary() {
1620
					"JavaCodeGenerator.variableLocal": true
...
3943
			add( new FormComponent( "javafx.scene.control.Label" ) {
4044
				name: "textLabel"
41
				"text": "Link Text:"
45
				"text": new FormMessage( null, "LinkDialog.textLabel.text" )
4246
				auxiliary() {
4347
					"JavaCodeGenerator.variableLocal": true
...
5458
			add( new FormComponent( "javafx.scene.control.Label" ) {
5559
				name: "titleLabel"
56
				"text": "Title (tooltip):"
60
				"text": new FormMessage( null, "LinkDialog.titleLabel.text" )
5761
				auxiliary() {
5862
					"JavaCodeGenerator.variableLocal": true
...
6872
			add( new FormComponent( "javafx.scene.control.Label" ) {
6973
				name: "previewLabel"
70
				"text": "Markdown Preview:"
74
				"text": new FormMessage( null, "LinkDialog.previewLabel.text" )
7175
				auxiliary() {
7276
					"JavaCodeGenerator.variableLocal": true
M src/main/java/org/markdownwriterfx/editor/MarkdownEditorPane.java
4444
import javafx.beans.property.SimpleObjectProperty;
4545
import javafx.beans.value.ObservableValue;
46
import javafx.event.EventHandler;
4746
import javafx.scene.Node;
4847
import javafx.scene.control.IndexRange;
...
126125
		Options.markdownExtensionsProperty().addListener(weakOptionsListener);
127126
		Options.showWhitespaceProperty().addListener(weakOptionsListener);
128
	}
129
130
	public void installEditorShortcuts(EventHandler<KeyEvent> editorShortcuts) {
131
		EventHandlerHelper.install(textArea.onKeyPressedProperty(), editorShortcuts);
132127
	}
133128
...
168163
	public void setMarkdown(String markdown) {
169164
		lineSeparator = determineLineSeparator(markdown);
170
		// always replace CRLF line separators to LF because RichTextFX does
171
		// not handle CRLF line separators well (e.g. need to press Backspace
172
		// or Del key twice to delete a CRLF line separator)
173
		markdown = markdown.replace("\r\n", "\n");
174165
		textArea.replaceText(markdown);
175166
		textArea.selectRange(0, 0);
...
235226
	private void deleteLine(KeyEvent e) {
236227
		int start = textArea.getCaretPosition() - textArea.getCaretColumn();
237
		int end = start + textArea.getParagraph(textArea.getCurrentParagraph()).fullLength();
228
		int end = start + textArea.getParagraph(textArea.getCurrentParagraph()).length() + 1;
238229
		textArea.deleteText(start, end);
239230
	}
M src/main/java/org/markdownwriterfx/editor/WhitespaceOverlayFactory.java
3030
import java.util.ArrayList;
3131
import java.util.Collection;
32
import java.util.Optional;
32
import javafx.collections.ObservableList;
3333
import javafx.geometry.Rectangle2D;
3434
import javafx.geometry.VPos;
3535
import javafx.scene.Node;
3636
import javafx.scene.text.Text;
37
import org.fxmisc.richtext.LineTerminator;
3837
import org.fxmisc.richtext.Paragraph;
3938
import org.fxmisc.richtext.StyledText;
...
5049
	@Override
5150
	public Node[] createOverlayNodes(int paragraphIndex) {
52
		Paragraph<Collection<String>> par = getTextArea().getParagraph(paragraphIndex);
51
		ObservableList<Paragraph<Collection<String>>> paragraphs = getTextArea().getParagraphs();
52
		Paragraph<Collection<String>> par = paragraphs.get(paragraphIndex);
5353
5454
		ArrayList<Node> nodes = new ArrayList<>();
...
7474
		}
7575
76
		Optional<LineTerminator> lineTerminator = par.getLineTerminator();
77
		if (lineTerminator.isPresent()) {
78
			String text;
79
			switch (lineTerminator.get()) {
80
				default:
81
				case LF:	text = "\u00B6"; break;
82
				case CR:	text = "\u00A4"; break;
83
				case CRLF:	text = "\u00A4\u00B6"; break;
84
			}
76
		if (paragraphIndex < paragraphs.size() - 1) {
77
			// all paragraphs except last one have line separators
8578
			Rectangle2D bounds = getBounds(segmentStart - 1, segmentStart);
8679
87
			nodes.add(createTextNode(text,
80
			nodes.add(createTextNode("\u00B6",
8881
					par.getStyleAtPosition(segmentStart),
8982
					bounds.getMaxX(),
M src/main/java/org/markdownwriterfx/options/GeneralOptionsPane.java
3535
import javafx.scene.control.ComboBox;
3636
import javafx.scene.control.Label;
37
import org.markdownwriterfx.Messages;
3738
import org.markdownwriterfx.util.Item;
3839
import org.tbee.javafx.scene.layout.fxml.MigPane;
...
5354
		String defaultLineSeparatorStr = defaultLineSeparator.replace("\r", "CR").replace("\n", "LF");
5455
		lineSeparatorField.getItems().addAll(
55
			new Item<String>( "Platform Default (" + defaultLineSeparatorStr + ')', null ),
56
			new Item<String>( "Windows (CRLF)", "\r\n" ),
57
			new Item<String>( "Unix (LF)", "\n" ));
56
			new Item<String>( Messages.get("GeneralOptionsPane.platformDefault", defaultLineSeparatorStr), null ),
57
			new Item<String>( Messages.get("GeneralOptionsPane.sepWindows"), "\r\n" ),
58
			new Item<String>( Messages.get("GeneralOptionsPane.sepUnix"), "\n" ));
5859
5960
		encodingField.getItems().addAll(getAvailableEncodings());
6061
	}
6162
6263
	private Collection<Item<String>> getAvailableEncodings() {
6364
		SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();
6465
6566
		ArrayList<Item<String>> values = new ArrayList<>(1 + availableCharsets.size());
66
		values.add(new Item<String>("Platform Default (" + Charset.defaultCharset().name() + ')', null));
67
		values.add(new Item<String>(Messages.get("GeneralOptionsPane.platformDefault", Charset.defaultCharset().name()), null));
6768
		for (String name : availableCharsets.keySet())
6869
			values.add(new Item<String>(name, name));
...
9899
99100
		//---- lineSeparatorLabel ----
100
		lineSeparatorLabel.setText("_Line separator:");
101
		lineSeparatorLabel.setText(Messages.get("GeneralOptionsPane.lineSeparatorLabel.text"));
101102
		lineSeparatorLabel.setMnemonicParsing(true);
102103
		add(lineSeparatorLabel, "cell 0 0");
103104
		add(lineSeparatorField, "cell 1 0");
104105
105106
		//---- lineSeparatorLabel2 ----
106
		lineSeparatorLabel2.setText("(applies to new files only)");
107
		lineSeparatorLabel2.setText(Messages.get("GeneralOptionsPane.lineSeparatorLabel2.text"));
107108
		add(lineSeparatorLabel2, "cell 2 0");
108109
109110
		//---- encodingLabel ----
110
		encodingLabel.setText("En_coding:");
111
		encodingLabel.setText(Messages.get("GeneralOptionsPane.encodingLabel.text"));
111112
		encodingLabel.setMnemonicParsing(true);
112113
		add(encodingLabel, "cell 0 1");
113114
114115
		//---- encodingField ----
115116
		encodingField.setVisibleRowCount(20);
116117
		add(encodingField, "cell 1 1");
117118
118119
		//---- showWhitespaceCheckBox ----
119
		showWhitespaceCheckBox.setText("Show _Whitespace Characters");
120
		showWhitespaceCheckBox.setText(Messages.get("GeneralOptionsPane.showWhitespaceCheckBox.text"));
120121
		add(showWhitespaceCheckBox, "cell 0 2 3 1,growx 0,alignx left");
121122
		// JFormDesigner - End of component initialization  //GEN-END:initComponents
M src/main/java/org/markdownwriterfx/options/GeneralOptionsPane.jfd
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_51" encoding: "UTF-8"
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_66" encoding: "UTF-8"
22
33
new FormModel {
4
	"i18n.bundlePackage": "org.markdownwriterfx"
5
	"i18n.bundleName": "messages"
6
	"i18n.autoExternalize": true
7
	"i18n.keyPrefix": "GeneralOptionsPane"
48
	contentType: "form/javafx"
59
	root: new FormRoot {
...
1216
			add( new FormComponent( "javafx.scene.control.Label" ) {
1317
				name: "lineSeparatorLabel"
14
				"text": "_Line separator:"
18
				"text": new FormMessage( null, "GeneralOptionsPane.lineSeparatorLabel.text" )
1519
				"mnemonicParsing": true
1620
				auxiliary() {
...
3034
			add( new FormComponent( "javafx.scene.control.Label" ) {
3135
				name: "lineSeparatorLabel2"
32
				"text": "(applies to new files only)"
36
				"text": new FormMessage( null, "GeneralOptionsPane.lineSeparatorLabel2.text" )
3337
				auxiliary() {
3438
					"JavaCodeGenerator.variableLocal": true
3539
				}
3640
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
3741
				"value": "cell 2 0"
3842
			} )
3943
			add( new FormComponent( "javafx.scene.control.Label" ) {
4044
				name: "encodingLabel"
41
				"text": "En_coding:"
45
				"text": new FormMessage( null, "GeneralOptionsPane.encodingLabel.text" )
4246
				"mnemonicParsing": true
4347
				auxiliary() {
...
5862
			add( new FormComponent( "javafx.scene.control.CheckBox" ) {
5963
				name: "showWhitespaceCheckBox"
60
				"text": "Show _Whitespace Characters"
64
				"text": new FormMessage( null, "GeneralOptionsPane.showWhitespaceCheckBox.text" )
6165
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
6266
				"value": "cell 0 2 3 1,growx 0,alignx left"
M src/main/java/org/markdownwriterfx/options/MarkdownOptionsPane.java
3131
import javafx.beans.property.SimpleIntegerProperty;
3232
import javafx.scene.control.Label;
33
import org.markdownwriterfx.Messages;
3334
import org.markdownwriterfx.controls.FlagCheckBox;
3435
import org.markdownwriterfx.controls.WebHyperlink;
...
6263
		suppressHtmlBlocksExtCheckBox.setFlag(Extensions.SUPPRESS_HTML_BLOCKS);
6364
		suppressInlineHtmlExtCheckBox.setFlag(Extensions.SUPPRESS_INLINE_HTML);
65
		atxHeaderSpaceExtCheckBox.setFlag(Extensions.ATXHEADERSPACE);
66
		forceListItemParaExtCheckBox.setFlag(Extensions.FORCELISTITEMPARA);
67
		relaxedHrRulesExtCheckBox.setFlag(Extensions.RELAXEDHRULES);
68
		taskListItemsExtCheckBox.setFlag(Extensions.TASKLISTITEMS);
69
		extAnchorLinksExtCheckBox.setFlag(Extensions.EXTANCHORLINKS);
6470
6571
		extensions.bindBidirectional(smartsExtCheckBox.flagsProperty());
...
7682
		extensions.bindBidirectional(suppressHtmlBlocksExtCheckBox.flagsProperty());
7783
		extensions.bindBidirectional(suppressInlineHtmlExtCheckBox.flagsProperty());
84
		extensions.bindBidirectional(atxHeaderSpaceExtCheckBox.flagsProperty());
85
		extensions.bindBidirectional(forceListItemParaExtCheckBox.flagsProperty());
86
		extensions.bindBidirectional(relaxedHrRulesExtCheckBox.flagsProperty());
87
		extensions.bindBidirectional(taskListItemsExtCheckBox.flagsProperty());
88
		extensions.bindBidirectional(extAnchorLinksExtCheckBox.flagsProperty());
7889
	}
7990
...
112123
		suppressHtmlBlocksExtCheckBox = new FlagCheckBox();
113124
		suppressInlineHtmlExtCheckBox = new FlagCheckBox();
125
		atxHeaderSpaceExtCheckBox = new FlagCheckBox();
126
		forceListItemParaExtCheckBox = new FlagCheckBox();
127
		relaxedHrRulesExtCheckBox = new FlagCheckBox();
128
		taskListItemsExtCheckBox = new FlagCheckBox();
129
		extAnchorLinksExtCheckBox = new FlagCheckBox();
114130
115131
		//======== this ========
116132
		setCols("[][fill]");
117
		setRows("[][][][][][][][][][][][][]");
133
		setRows("[][][][][][][][][][][][][][][][][][]");
118134
119135
		//---- smartsExtCheckBox ----
120
		smartsExtCheckBox.setText("Beautify apostrophes, _ellipses (\"...\" and \". . .\") and dashes (\"--\" and \"---\")");
136
		smartsExtCheckBox.setText(Messages.get("MarkdownOptionsPane.smartsExtCheckBox.text"));
121137
		add(smartsExtCheckBox, "cell 0 0");
122138
123139
		//---- quotesExtCheckBox ----
124
		quotesExtCheckBox.setText("Beautify single _quotes, double quotes and double angle quotes (\u00ab and \u00bb)");
140
		quotesExtCheckBox.setText(Messages.get("MarkdownOptionsPane.quotesExtCheckBox.text"));
125141
		add(quotesExtCheckBox, "cell 0 1");
126142
127143
		//---- abbreviationsExtCheckBox ----
128
		abbreviationsExtCheckBox.setText("A_bbreviations in the way of");
144
		abbreviationsExtCheckBox.setText(Messages.get("MarkdownOptionsPane.abbreviationsExtCheckBox.text"));
129145
		add(abbreviationsExtCheckBox, "cell 0 2");
130146
131147
		//---- abbreviationsExtLink ----
132
		abbreviationsExtLink.setText("Markdown Extra");
148
		abbreviationsExtLink.setText(Messages.get("MarkdownOptionsPane.abbreviationsExtLink.text"));
133149
		abbreviationsExtLink.setUri("http://michelf.com/projects/php-markdown/extra/#abbr");
134150
		add(abbreviationsExtLink, "cell 0 2,gapx 0");
135151
136152
		//---- hardwrapsExtCheckBox ----
137
		hardwrapsExtCheckBox.setText("_Newlines in paragraph-like content as real line breaks, see");
153
		hardwrapsExtCheckBox.setText(Messages.get("MarkdownOptionsPane.hardwrapsExtCheckBox.text"));
138154
		add(hardwrapsExtCheckBox, "cell 0 3");
139155
140156
		//---- hardwrapsExtLink ----
141
		hardwrapsExtLink.setText("Github-flavoured-Markdown");
157
		hardwrapsExtLink.setText(Messages.get("MarkdownOptionsPane.hardwrapsExtLink.text"));
142158
		hardwrapsExtLink.setUri("https://help.github.com/articles/writing-on-github/#markup");
143159
		add(hardwrapsExtLink, "cell 0 3,gapx 0");
144160
145161
		//---- autolinksExtCheckBox ----
146
		autolinksExtCheckBox.setText("_Plain (undelimited) autolinks in the way of");
162
		autolinksExtCheckBox.setText(Messages.get("MarkdownOptionsPane.autolinksExtCheckBox.text"));
147163
		add(autolinksExtCheckBox, "cell 0 4");
148164
149165
		//---- autolinksExtLink ----
150
		autolinksExtLink.setText("Github-flavoured-Markdown");
166
		autolinksExtLink.setText(Messages.get("MarkdownOptionsPane.autolinksExtLink.text"));
151167
		autolinksExtLink.setUri("https://help.github.com/articles/github-flavored-markdown/#url-autolinking");
152168
		add(autolinksExtLink, "cell 0 4,gapx 0");
153169
154170
		//---- tablesExtCheckBox ----
155
		tablesExtCheckBox.setText("_Tables similar to");
171
		tablesExtCheckBox.setText(Messages.get("MarkdownOptionsPane.tablesExtCheckBox.text"));
156172
		add(tablesExtCheckBox, "cell 0 5");
157173
158174
		//---- tablesExtLink ----
159
		tablesExtLink.setText("MultiMarkdown");
175
		tablesExtLink.setText(Messages.get("MarkdownOptionsPane.tablesExtLink.text"));
160176
		tablesExtLink.setUri("http://fletcher.github.io/MultiMarkdown-4/syntax.html#tables");
161177
		add(tablesExtLink, "cell 0 5,gapx 0");
162178
163179
		//---- tablesExtLabel ----
164
		tablesExtLabel.setText("(like");
180
		tablesExtLabel.setText(Messages.get("MarkdownOptionsPane.tablesExtLabel.text"));
165181
		add(tablesExtLabel, "cell 0 5,gapx 3");
166182
167183
		//---- tablesExtLink2 ----
168
		tablesExtLink2.setText("Markdown Extra");
184
		tablesExtLink2.setText(Messages.get("MarkdownOptionsPane.tablesExtLink2.text"));
169185
		tablesExtLink2.setUri("https://michelf.ca/projects/php-markdown/extra/#table");
170186
		add(tablesExtLink2, "cell 0 5,gapx 3 3");
171187
172188
		//---- tablesExtLabel2 ----
173
		tablesExtLabel2.setText(" tables, but with colspan support)");
189
		tablesExtLabel2.setText(Messages.get("MarkdownOptionsPane.tablesExtLabel2.text"));
174190
		add(tablesExtLabel2, "cell 0 5,gapx 0");
175191
176192
		//---- definitionListsExtCheckBox ----
177
		definitionListsExtCheckBox.setText("_Definition lists in the way of");
193
		definitionListsExtCheckBox.setText(Messages.get("MarkdownOptionsPane.definitionListsExtCheckBox.text"));
178194
		add(definitionListsExtCheckBox, "cell 0 6");
179195
180196
		//---- definitionListsExtLink ----
181
		definitionListsExtLink.setText("Markdown Extra");
197
		definitionListsExtLink.setText(Messages.get("MarkdownOptionsPane.definitionListsExtLink.text"));
182198
		definitionListsExtLink.setUri("https://michelf.ca/projects/php-markdown/extra/#def-list");
183199
		add(definitionListsExtLink, "cell 0 6,gapx 0");
184200
185201
		//---- fencedCodeBlocksExtCheckBox ----
186
		fencedCodeBlocksExtCheckBox.setText("_Fenced Code Blocks in the way of");
202
		fencedCodeBlocksExtCheckBox.setText(Messages.get("MarkdownOptionsPane.fencedCodeBlocksExtCheckBox.text"));
187203
		add(fencedCodeBlocksExtCheckBox, "cell 0 7");
188204
189205
		//---- fencedCodeBlocksExtLink ----
190
		fencedCodeBlocksExtLink.setText("Markdown Extra");
206
		fencedCodeBlocksExtLink.setText(Messages.get("MarkdownOptionsPane.fencedCodeBlocksExtLink.text"));
191207
		fencedCodeBlocksExtLink.setUri("http://michelf.com/projects/php-markdown/extra/#fenced-code-blocks");
192208
		add(fencedCodeBlocksExtLink, "cell 0 7,gapx 0");
193209
194210
		//---- fencedCodeBlocksExtLabel ----
195
		fencedCodeBlocksExtLabel.setText("or");
211
		fencedCodeBlocksExtLabel.setText(Messages.get("MarkdownOptionsPane.fencedCodeBlocksExtLabel.text"));
196212
		add(fencedCodeBlocksExtLabel, "cell 0 7,gapx 3");
197213
198214
		//---- fencedCodeBlocksExtLink2 ----
199
		fencedCodeBlocksExtLink2.setText("Github-flavoured-Markdown");
215
		fencedCodeBlocksExtLink2.setText(Messages.get("MarkdownOptionsPane.fencedCodeBlocksExtLink2.text"));
200216
		fencedCodeBlocksExtLink2.setUri("https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks");
201217
		add(fencedCodeBlocksExtLink2, "cell 0 7,gapx 3");
202218
203219
		//---- wikilinksExtCheckBox ----
204
		wikilinksExtCheckBox.setText("_Wiki-style links (\"[[wiki link]]\")");
220
		wikilinksExtCheckBox.setText(Messages.get("MarkdownOptionsPane.wikilinksExtCheckBox.text"));
205221
		add(wikilinksExtCheckBox, "cell 0 8");
206222
207223
		//---- strikethroughExtCheckBox ----
208
		strikethroughExtCheckBox.setText("_Strikethrough");
224
		strikethroughExtCheckBox.setText(Messages.get("MarkdownOptionsPane.strikethroughExtCheckBox.text"));
209225
		add(strikethroughExtCheckBox, "cell 0 9");
210226
211227
		//---- anchorlinksExtCheckBox ----
212
		anchorlinksExtCheckBox.setText("_Anchor links in headers");
228
		anchorlinksExtCheckBox.setText(Messages.get("MarkdownOptionsPane.anchorlinksExtCheckBox.text"));
213229
		add(anchorlinksExtCheckBox, "cell 0 10");
214230
215231
		//---- suppressHtmlBlocksExtCheckBox ----
216
		suppressHtmlBlocksExtCheckBox.setText("Suppress the _output of HTML blocks");
232
		suppressHtmlBlocksExtCheckBox.setText(Messages.get("MarkdownOptionsPane.suppressHtmlBlocksExtCheckBox.text"));
217233
		add(suppressHtmlBlocksExtCheckBox, "cell 0 11");
218234
219235
		//---- suppressInlineHtmlExtCheckBox ----
220
		suppressInlineHtmlExtCheckBox.setText("Suppress the o_utput of inline HTML elements");
236
		suppressInlineHtmlExtCheckBox.setText(Messages.get("MarkdownOptionsPane.suppressInlineHtmlExtCheckBox.text"));
221237
		add(suppressInlineHtmlExtCheckBox, "cell 0 12");
238
239
		//---- atxHeaderSpaceExtCheckBox ----
240
		atxHeaderSpaceExtCheckBox.setText(Messages.get("MarkdownOptionsPane.atxHeaderSpaceExtCheckBox.text"));
241
		add(atxHeaderSpaceExtCheckBox, "cell 0 13");
242
243
		//---- forceListItemParaExtCheckBox ----
244
		forceListItemParaExtCheckBox.setText(Messages.get("MarkdownOptionsPane.forceListItemParaExtCheckBox.text"));
245
		add(forceListItemParaExtCheckBox, "cell 0 14");
246
247
		//---- relaxedHrRulesExtCheckBox ----
248
		relaxedHrRulesExtCheckBox.setText(Messages.get("MarkdownOptionsPane.relaxedHrRulesExtCheckBox.text"));
249
		add(relaxedHrRulesExtCheckBox, "cell 0 15");
250
251
		//---- taskListItemsExtCheckBox ----
252
		taskListItemsExtCheckBox.setText(Messages.get("MarkdownOptionsPane.taskListItemsExtCheckBox.text"));
253
		add(taskListItemsExtCheckBox, "cell 0 16");
254
255
		//---- extAnchorLinksExtCheckBox ----
256
		extAnchorLinksExtCheckBox.setText(Messages.get("MarkdownOptionsPane.extAnchorLinksExtCheckBox.text"));
257
		add(extAnchorLinksExtCheckBox, "cell 0 17");
222258
		// JFormDesigner - End of component initialization  //GEN-END:initComponents
223259
	}
...
237273
	private FlagCheckBox suppressHtmlBlocksExtCheckBox;
238274
	private FlagCheckBox suppressInlineHtmlExtCheckBox;
275
	private FlagCheckBox atxHeaderSpaceExtCheckBox;
276
	private FlagCheckBox forceListItemParaExtCheckBox;
277
	private FlagCheckBox relaxedHrRulesExtCheckBox;
278
	private FlagCheckBox taskListItemsExtCheckBox;
279
	private FlagCheckBox extAnchorLinksExtCheckBox;
239280
	// JFormDesigner - End of variables declaration  //GEN-END:variables
240281
}
M src/main/java/org/markdownwriterfx/options/MarkdownOptionsPane.jfd
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_51" encoding: "UTF-8"
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_66" encoding: "UTF-8"
22
33
new FormModel {
4
	"i18n.bundlePackage": "org.markdownwriterfx"
5
	"i18n.bundleName": "messages"
6
	"i18n.autoExternalize": true
7
	"i18n.keyPrefix": "MarkdownOptionsPane"
48
	contentType: "form/javafx"
59
	root: new FormRoot {
610
		add( new FormContainer( "org.tbee.javafx.scene.layout.fxml.MigPane", new FormLayoutManager( class org.tbee.javafx.scene.layout.fxml.MigPane ) {
7
			"$rowConstraints": "[][][][][][][][][][][][][]"
11
			"$rowConstraints": "[][][][][][][][][][][][][][][][][][]"
812
			"$columnConstraints": "[][fill]"
913
		} ) {
1014
			name: "this"
1115
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
1216
				name: "smartsExtCheckBox"
13
				"text": "Beautify apostrophes, _ellipses (\"...\" and \". . .\") and dashes (\"--\" and \"---\")"
17
				"text": new FormMessage( null, "MarkdownOptionsPane.smartsExtCheckBox.text" )
1418
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
1519
				"value": "cell 0 0"
1620
			} )
1721
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
1822
				name: "quotesExtCheckBox"
19
				"text": "Beautify single _quotes, double quotes and double angle quotes (« and »)"
23
				"text": new FormMessage( null, "MarkdownOptionsPane.quotesExtCheckBox.text" )
2024
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
2125
				"value": "cell 0 1"
2226
			} )
2327
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
2428
				name: "abbreviationsExtCheckBox"
25
				"text": "A_bbreviations in the way of"
29
				"text": new FormMessage( null, "MarkdownOptionsPane.abbreviationsExtCheckBox.text" )
2630
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
2731
				"value": "cell 0 2"
2832
			} )
2933
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
3034
				name: "abbreviationsExtLink"
31
				"text": "Markdown Extra"
35
				"text": new FormMessage( null, "MarkdownOptionsPane.abbreviationsExtLink.text" )
3236
				"uri": "http://michelf.com/projects/php-markdown/extra/#abbr"
3337
				auxiliary() {
3438
					"JavaCodeGenerator.variableLocal": true
3539
				}
3640
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
3741
				"value": "cell 0 2,gapx 0"
3842
			} )
3943
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
4044
				name: "hardwrapsExtCheckBox"
41
				"text": "_Newlines in paragraph-like content as real line breaks, see"
45
				"text": new FormMessage( null, "MarkdownOptionsPane.hardwrapsExtCheckBox.text" )
4246
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
4347
				"value": "cell 0 3"
4448
			} )
4549
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
4650
				name: "hardwrapsExtLink"
47
				"text": "Github-flavoured-Markdown"
51
				"text": new FormMessage( null, "MarkdownOptionsPane.hardwrapsExtLink.text" )
4852
				"uri": "https://help.github.com/articles/writing-on-github/#markup"
4953
				auxiliary() {
5054
					"JavaCodeGenerator.variableLocal": true
5155
				}
5256
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
5357
				"value": "cell 0 3,gapx 0"
5458
			} )
5559
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
5660
				name: "autolinksExtCheckBox"
57
				"text": "_Plain (undelimited) autolinks in the way of"
61
				"text": new FormMessage( null, "MarkdownOptionsPane.autolinksExtCheckBox.text" )
5862
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
5963
				"value": "cell 0 4"
6064
			} )
6165
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
6266
				name: "autolinksExtLink"
63
				"text": "Github-flavoured-Markdown"
67
				"text": new FormMessage( null, "MarkdownOptionsPane.autolinksExtLink.text" )
6468
				"uri": "https://help.github.com/articles/github-flavored-markdown/#url-autolinking"
6569
				auxiliary() {
6670
					"JavaCodeGenerator.variableLocal": true
6771
				}
6872
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
6973
				"value": "cell 0 4,gapx 0"
7074
			} )
7175
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
7276
				name: "tablesExtCheckBox"
73
				"text": "_Tables similar to"
77
				"text": new FormMessage( null, "MarkdownOptionsPane.tablesExtCheckBox.text" )
7478
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
7579
				"value": "cell 0 5"
7680
			} )
7781
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
7882
				name: "tablesExtLink"
79
				"text": "MultiMarkdown"
83
				"text": new FormMessage( null, "MarkdownOptionsPane.tablesExtLink.text" )
8084
				"uri": "http://fletcher.github.io/MultiMarkdown-4/syntax.html#tables"
8185
				auxiliary() {
8286
					"JavaCodeGenerator.variableLocal": true
8387
				}
8488
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
8589
				"value": "cell 0 5,gapx 0"
8690
			} )
8791
			add( new FormComponent( "javafx.scene.control.Label" ) {
8892
				name: "tablesExtLabel"
89
				"text": "(like"
93
				"text": new FormMessage( null, "MarkdownOptionsPane.tablesExtLabel.text" )
9094
				auxiliary() {
9195
					"JavaCodeGenerator.variableLocal": true
9296
				}
9397
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
9498
				"value": "cell 0 5,gapx 3"
9599
			} )
96100
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
97101
				name: "tablesExtLink2"
98
				"text": "Markdown Extra"
102
				"text": new FormMessage( null, "MarkdownOptionsPane.tablesExtLink2.text" )
99103
				"uri": "https://michelf.ca/projects/php-markdown/extra/#table"
100104
				auxiliary() {
101105
					"JavaCodeGenerator.variableLocal": true
102106
				}
103107
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
104108
				"value": "cell 0 5,gapx 3 3"
105109
			} )
106110
			add( new FormComponent( "javafx.scene.control.Label" ) {
107111
				name: "tablesExtLabel2"
108
				"text": " tables, but with colspan support)"
112
				"text": new FormMessage( null, "MarkdownOptionsPane.tablesExtLabel2.text" )
109113
				auxiliary() {
110114
					"JavaCodeGenerator.variableLocal": true
111115
				}
112116
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
113117
				"value": "cell 0 5,gapx 0"
114118
			} )
115119
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
116120
				name: "definitionListsExtCheckBox"
117
				"text": "_Definition lists in the way of"
121
				"text": new FormMessage( null, "MarkdownOptionsPane.definitionListsExtCheckBox.text" )
118122
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
119123
				"value": "cell 0 6"
120124
			} )
121125
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
122126
				name: "definitionListsExtLink"
123
				"text": "Markdown Extra"
127
				"text": new FormMessage( null, "MarkdownOptionsPane.definitionListsExtLink.text" )
124128
				"uri": "https://michelf.ca/projects/php-markdown/extra/#def-list"
125129
				auxiliary() {
126130
					"JavaCodeGenerator.variableLocal": true
127131
				}
128132
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
129133
				"value": "cell 0 6,gapx 0"
130134
			} )
131135
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
132136
				name: "fencedCodeBlocksExtCheckBox"
133
				"text": "_Fenced Code Blocks in the way of"
137
				"text": new FormMessage( null, "MarkdownOptionsPane.fencedCodeBlocksExtCheckBox.text" )
134138
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
135139
				"value": "cell 0 7"
136140
			} )
137141
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
138142
				name: "fencedCodeBlocksExtLink"
139
				"text": "Markdown Extra"
143
				"text": new FormMessage( null, "MarkdownOptionsPane.fencedCodeBlocksExtLink.text" )
140144
				"uri": "http://michelf.com/projects/php-markdown/extra/#fenced-code-blocks"
141145
				auxiliary() {
142146
					"JavaCodeGenerator.variableLocal": true
143147
				}
144148
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
145149
				"value": "cell 0 7,gapx 0"
146150
			} )
147151
			add( new FormComponent( "javafx.scene.control.Label" ) {
148152
				name: "fencedCodeBlocksExtLabel"
149
				"text": "or"
153
				"text": new FormMessage( null, "MarkdownOptionsPane.fencedCodeBlocksExtLabel.text" )
150154
				auxiliary() {
151155
					"JavaCodeGenerator.variableLocal": true
152156
				}
153157
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
154158
				"value": "cell 0 7,gapx 3"
155159
			} )
156160
			add( new FormComponent( "org.markdownwriterfx.controls.WebHyperlink" ) {
157161
				name: "fencedCodeBlocksExtLink2"
158
				"text": "Github-flavoured-Markdown"
162
				"text": new FormMessage( null, "MarkdownOptionsPane.fencedCodeBlocksExtLink2.text" )
159163
				"uri": "https://help.github.com/articles/github-flavored-markdown/#fenced-code-blocks"
160164
				auxiliary() {
161165
					"JavaCodeGenerator.variableLocal": true
162166
				}
163167
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
164168
				"value": "cell 0 7,gapx 3"
165169
			} )
166170
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
167171
				name: "wikilinksExtCheckBox"
168
				"text": "_Wiki-style links (\"[[wiki link]]\")"
172
				"text": new FormMessage( null, "MarkdownOptionsPane.wikilinksExtCheckBox.text" )
169173
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
170174
				"value": "cell 0 8"
171175
			} )
172176
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
173177
				name: "strikethroughExtCheckBox"
174
				"text": "_Strikethrough"
178
				"text": new FormMessage( null, "MarkdownOptionsPane.strikethroughExtCheckBox.text" )
175179
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
176180
				"value": "cell 0 9"
177181
			} )
178182
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
179183
				name: "anchorlinksExtCheckBox"
180
				"text": "_Anchor links in headers"
184
				"text": new FormMessage( null, "MarkdownOptionsPane.anchorlinksExtCheckBox.text" )
181185
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
182186
				"value": "cell 0 10"
183187
			} )
184188
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
185189
				name: "suppressHtmlBlocksExtCheckBox"
186
				"text": "Suppress the _output of HTML blocks"
190
				"text": new FormMessage( null, "MarkdownOptionsPane.suppressHtmlBlocksExtCheckBox.text" )
187191
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
188192
				"value": "cell 0 11"
189193
			} )
190194
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
191195
				name: "suppressInlineHtmlExtCheckBox"
192
				"text": "Suppress the o_utput of inline HTML elements"
196
				"text": new FormMessage( null, "MarkdownOptionsPane.suppressInlineHtmlExtCheckBox.text" )
193197
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
194198
				"value": "cell 0 12"
199
			} )
200
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
201
				name: "atxHeaderSpaceExtCheckBox"
202
				"text": new FormMessage( null, "MarkdownOptionsPane.atxHeaderSpaceExtCheckBox.text" )
203
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
204
				"value": "cell 0 13"
205
			} )
206
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
207
				name: "forceListItemParaExtCheckBox"
208
				"text": new FormMessage( null, "MarkdownOptionsPane.forceListItemParaExtCheckBox.text" )
209
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
210
				"value": "cell 0 14"
211
			} )
212
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
213
				name: "relaxedHrRulesExtCheckBox"
214
				"text": new FormMessage( null, "MarkdownOptionsPane.relaxedHrRulesExtCheckBox.text" )
215
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
216
				"value": "cell 0 15"
217
			} )
218
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
219
				name: "taskListItemsExtCheckBox"
220
				"text": new FormMessage( null, "MarkdownOptionsPane.taskListItemsExtCheckBox.text" )
221
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
222
				"value": "cell 0 16"
223
			} )
224
			add( new FormComponent( "org.markdownwriterfx.controls.FlagCheckBox" ) {
225
				name: "extAnchorLinksExtCheckBox"
226
				"text": new FormMessage( null, "MarkdownOptionsPane.extAnchorLinksExtCheckBox.text" )
227
			}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
228
				"value": "cell 0 17"
195229
			} )
196230
		}, new FormLayoutConstraints( null ) {
M src/main/java/org/markdownwriterfx/options/OptionsDialog.java
3636
import javafx.stage.Window;
3737
import org.markdownwriterfx.MarkdownWriterFXApp;
38
import org.markdownwriterfx.Messages;
3839
3940
/**
...
4647
{
4748
	public OptionsDialog(Window owner) {
48
		setTitle("Options");
49
		setTitle(Messages.get("OptionsDialog.title"));
4950
		initOwner(owner);
5051
...
102103
			//======== generalTab ========
103104
			{
104
				generalTab.setText("General");
105
				generalTab.setText(Messages.get("OptionsDialog.generalTab.text"));
105106
				generalTab.setContent(generalOptionsPane);
106107
			}
107108
108109
			//======== markdownTab ========
109110
			{
110
				markdownTab.setText("Markdown");
111
				markdownTab.setText(Messages.get("OptionsDialog.markdownTab.text"));
111112
				markdownTab.setContent(markdownOptionsPane);
112113
			}
M src/main/java/org/markdownwriterfx/options/OptionsDialog.jfd
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_51" encoding: "UTF-8"
1
JFDML JFormDesigner: "9.9.9.9.9999" Java: "1.8.0_66" encoding: "UTF-8"
22
33
new FormModel {
4
	"i18n.bundlePackage": "org.markdownwriterfx"
5
	"i18n.bundleName": "messages"
6
	"i18n.keyPrefix": "OptionsDialog"
7
	"i18n.autoExternalize": true
48
	contentType: "form/javafx"
59
	root: new FormRoot {
610
		add( new FormContainer( "javafx.scene.control.TabPane", new FormLayoutManager( class javafx.scene.control.TabPane ) ) {
711
			name: "tabPane"
812
			"tabClosingPolicy": enum javafx.scene.control.TabPane$TabClosingPolicy UNAVAILABLE
913
			add( new FormContainer( "javafx.scene.control.Tab", new FormLayoutManager( class javafx.scene.control.Tab ) ) {
1014
				name: "generalTab"
11
				"text": "General"
15
				"text": new FormMessage( null, "OptionsDialog.generalTab.text" )
1216
				add( new FormComponent( "org.markdownwriterfx.options.GeneralOptionsPane" ) {
1317
					name: "generalOptionsPane"
1418
				} )
1519
			} )
1620
			add( new FormContainer( "javafx.scene.control.Tab", new FormLayoutManager( class javafx.scene.control.Tab ) ) {
1721
				name: "markdownTab"
18
				"text": "Markdown"
22
				"text": new FormMessage( null, "OptionsDialog.markdownTab.text" )
1923
				add( new FormComponent( "org.markdownwriterfx.options.MarkdownOptionsPane" ) {
2024
					name: "markdownOptionsPane"
M src/main/java/org/markdownwriterfx/preview/MarkdownPreviewPane.java
3939
import javafx.scene.control.TabPane;
4040
import javafx.scene.control.TabPane.TabClosingPolicy;
41
import org.markdownwriterfx.Messages;
4142
import org.pegdown.ast.RootNode;
4243
...
6465
		tabPane.setTabClosingPolicy(TabClosingPolicy.UNAVAILABLE);
6566
66
		Tab webViewTab = new Tab("Preview", webViewPreview.getNode());
67
		Tab webViewTab = new Tab(Messages.get("MarkdownPreviewPane.webViewTab"), webViewPreview.getNode());
6768
		webViewTab.setUserData(webViewPreview);
6869
		tabPane.getTabs().add(webViewTab);
6970
70
		Tab htmlSourceTab = new Tab("HTML Source", htmlSourcePreview.getNode());
71
		Tab htmlSourceTab = new Tab(Messages.get("MarkdownPreviewPane.htmlSourceTab"), htmlSourcePreview.getNode());
7172
		htmlSourceTab.setUserData(htmlSourcePreview);
7273
		tabPane.getTabs().add(htmlSourceTab);
7374
74
		Tab astTab = new Tab("Markdown AST", astPreview.getNode());
75
		Tab astTab = new Tab(Messages.get("MarkdownPreviewPane.astTab"), astPreview.getNode());
7576
		astTab.setUserData(astPreview);
7677
		tabPane.getTabs().add(astTab);
A src/main/resources/org/markdownwriterfx/messages.properties
1
#
2
# Copyright (c) 2016 Karl Tauber <karl at jformdesigner dot com>
3
# All rights reserved.
4
#
5
# Redistribution and use in source and binary forms, with or without
6
# modification, are permitted provided that the following conditions are met:
7
#
8
#  * Redistributions of source code must retain the above copyright
9
#    notice, this list of conditions and the following disclaimer.
10
#
11
#  * Redistributions in binary form must reproduce the above copyright
12
#    notice, this list of conditions and the following disclaimer in the
13
#    documentation and/or other materials provided with the distribution.
14
#
15
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19
# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
#
27
28
#---- MainWindow ----
29
30
MainWindow.fileMenu=File
31
MainWindow.fileNewAction=New
32
MainWindow.fileOpenAction=Open...
33
MainWindow.fileCloseAction=Close
34
MainWindow.fileCloseAllAction=Close All
35
MainWindow.fileSaveAction=Save
36
MainWindow.fileSaveAllAction=Save All
37
MainWindow.fileExitAction=Exit
38
39
MainWindow.editMenu=Edit
40
MainWindow.editUndoAction=Undo
41
MainWindow.editRedoAction=Redo
42
43
MainWindow.insertMenu=Insert
44
MainWindow.insertBoldAction=Bold
45
MainWindow.insertItalicAction=Italic
46
MainWindow.insertStrikethroughAction=Strikethrough
47
MainWindow.insertBlockquoteAction=Blockquote
48
MainWindow.insertCodeAction=Inline Code
49
MainWindow.insertFencedCodeBlockAction=Fenced Code Block
50
MainWindow.insertFencedCodeBlockText=enter code here
51
MainWindow.insertLinkAction=Link...
52
MainWindow.insertImageAction=Image...
53
MainWindow.insertHeader1Action=Header 1
54
MainWindow.insertHeader1Text=header 1
55
MainWindow.insertHeader2Action=Header 2
56
MainWindow.insertHeader2Text=header 2
57
MainWindow.insertHeader3Action=Header 3
58
MainWindow.insertHeader3Text=header 3
59
MainWindow.insertHeader4Action=Header 4
60
MainWindow.insertHeader4Text=header 4
61
MainWindow.insertHeader5Action=Header 5
62
MainWindow.insertHeader5Text=header 5
63
MainWindow.insertHeader6Action=Header 6
64
MainWindow.insertHeader6Text=header 6
65
MainWindow.insertUnorderedListAction=Unordered List
66
MainWindow.insertOrderedListAction=Ordered List
67
MainWindow.insertHorizontalRuleAction=Horizontal Rule
68
69
MainWindow.toolsMenu=Tools
70
MainWindow.toolsOptionsAction=Options
71
72
MainWindow.helpMenu=Help
73
MainWindow.helpAboutAction=About Markdown Writer FX
74
75
MainWindow.about.title=About
76
MainWindow.about.headerText=Markdown Writer FX
77
MainWindow.about.contentText=Copyright (c) 2015 Karl Tauber <karl at jformdesigner dot com>\nAll rights reserved.
78
79
80
#---- FileEditor ----
81
82
FileEditor.untitled=Untitled
83
FileEditor.loadFailed.message=Failed to load ''{0}''.\n\nReason: {1}
84
FileEditor.loadFailed.title=Load
85
FileEditor.saveFailed.message=Failed to save ''{0}''.\n\nReason: {1}
86
FileEditor.saveFailed.title=Save
87
88
89
#---- FileEditorTabPane ----
90
91
FileEditorTabPane.openChooser.title=Open Markdown File
92
FileEditorTabPane.saveChooser.title=Save Markdown File
93
FileEditorTabPane.closeAlert.message=''{0}'' has been modified. Save changes?
94
FileEditorTabPane.closeAlert.title=Close
95
FileEditorTabPane.chooser.markdownFilesFilter=Markdown Files
96
FileEditorTabPane.chooser.allFilesFilter=All Files
97
98
99
#==== Controls ================================================================
100
101
#---- BrowseDirectoryButton ----
102
103
BrowseDirectoryButton.tooltip=Browse for local folder
104
BrowseDirectoryButton.chooser.title=Browse for local folder
105
106
107
#---- BrowseFileButton ----
108
109
BrowseFileButton.tooltip=Browse for local file
110
BrowseFileButton.chooser.title=Browse for local file
111
BrowseFileButton.chooser.allFilesFilter=All Files
112
113
114
#==== Dialogs =================================================================
115
116
#---- ImageDialog ----
117
118
ImageDialog.title=Image
119
ImageDialog.chooser.imagesFilter=Images
120
ImageDialog.previewLabel.text=Markdown Preview\:
121
ImageDialog.textLabel.text=Alternate Text\:
122
ImageDialog.titleLabel.text=Title (tooltip)\:
123
ImageDialog.urlLabel.text=Image URL\:
124
125
126
#---- LinkDialog ----
127
128
LinkDialog.title=Link
129
LinkDialog.previewLabel.text=Markdown Preview\:
130
LinkDialog.textLabel.text=Link Text\:
131
LinkDialog.titleLabel.text=Title (tooltip)\:
132
LinkDialog.urlLabel.text=Link URL\:
133
134
135
#==== Options =================================================================
136
137
#---- OptionsDialog ----
138
139
OptionsDialog.title=Options
140
OptionsDialog.generalTab.text=General
141
OptionsDialog.markdownTab.text=Markdown
142
143
144
#---- GeneralOptionsPane ----
145
146
GeneralOptionsPane.encodingLabel.text=En_coding\:
147
GeneralOptionsPane.lineSeparatorLabel.text=_Line separator\:
148
GeneralOptionsPane.lineSeparatorLabel2.text=(applies to new files only)
149
GeneralOptionsPane.showWhitespaceCheckBox.text=Show _Whitespace Characters
150
151
GeneralOptionsPane.platformDefault=Platform Default ({0})
152
GeneralOptionsPane.sepWindows=Windows (CRLF)
153
GeneralOptionsPane.sepUnix=Unix (LF)
154
155
156
#---- MarkdownOptionsPane ----
157
158
MarkdownOptionsPane.abbreviationsExtCheckBox.text=A_bbreviations in the way of
159
MarkdownOptionsPane.abbreviationsExtLink.text=Markdown Extra
160
MarkdownOptionsPane.anchorlinksExtCheckBox.text=_Anchor links in headers
161
MarkdownOptionsPane.atxHeaderSpaceExtCheckBox.text=Requires a space char after Atx \# header prefixes, so that \#dasdsdaf is not a header
162
MarkdownOptionsPane.autolinksExtCheckBox.text=_Plain (undelimited) autolinks in the way of
163
MarkdownOptionsPane.autolinksExtLink.text=Github-flavoured-Markdown
164
MarkdownOptionsPane.definitionListsExtCheckBox.text=_Definition lists in the way of
165
MarkdownOptionsPane.definitionListsExtLink.text=Markdown Extra
166
MarkdownOptionsPane.extAnchorLinksExtCheckBox.text=Generate anchor links for headers using complete contents of the header
167
MarkdownOptionsPane.fencedCodeBlocksExtCheckBox.text=_Fenced Code Blocks in the way of
168
MarkdownOptionsPane.fencedCodeBlocksExtLabel.text=or
169
MarkdownOptionsPane.fencedCodeBlocksExtLink.text=Markdown Extra
170
MarkdownOptionsPane.fencedCodeBlocksExtLink2.text=Github-flavoured-Markdown
171
MarkdownOptionsPane.forceListItemParaExtCheckBox.text=Force List and Definition Paragraph wrapping if it includes more than just a single paragraph
172
MarkdownOptionsPane.hardwrapsExtCheckBox.text=_Newlines in paragraph-like content as real line breaks, see
173
MarkdownOptionsPane.hardwrapsExtLink.text=Github-flavoured-Markdown
174
MarkdownOptionsPane.quotesExtCheckBox.text=Beautify single _quotes, double quotes and double angle quotes (� and �)
175
MarkdownOptionsPane.relaxedHrRulesExtCheckBox.text=Allow horizontal rules without a blank line following them
176
MarkdownOptionsPane.smartsExtCheckBox.text=Beautify apostrophes, _ellipses ("..." and ". . .") and dashes ("--" and "---")
177
MarkdownOptionsPane.strikethroughExtCheckBox.text=_Strikethrough
178
MarkdownOptionsPane.suppressHtmlBlocksExtCheckBox.text=Suppress the _output of HTML blocks
179
MarkdownOptionsPane.suppressInlineHtmlExtCheckBox.text=Suppress the o_utput of inline HTML elements
180
MarkdownOptionsPane.tablesExtCheckBox.text=_Tables similar to
181
MarkdownOptionsPane.tablesExtLabel.text=(like
182
MarkdownOptionsPane.tablesExtLabel2.text=tables, but with colspan support)
183
MarkdownOptionsPane.tablesExtLink.text=MultiMarkdown
184
MarkdownOptionsPane.tablesExtLink2.text=Markdown Extra
185
MarkdownOptionsPane.taskListItemsExtCheckBox.text=GitHub style task list items
186
MarkdownOptionsPane.wikilinksExtCheckBox.text=_Wiki-style links ("[[wiki link]]")
187
188
189
#===== preview ================================================================
190
191
#---- MarkdownPreviewPane ----
192
193
MarkdownPreviewPane.astTab=Markdown AST
194
MarkdownPreviewPane.htmlSourceTab=HTML Source
195
MarkdownPreviewPane.webViewTab=Preview
1196