Skip to content

Commit 21865ee

Browse files
committed
formatting toolbar items (bold, italic, etc) are highlighted if the caret in the editor is at formatted text
1 parent 16a46d7 commit 21865ee

5 files changed

Lines changed: 167 additions & 10 deletions

File tree

CHANGES.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Markdown Writer FX Change Log
66
- Highlight paragraph in Preview that contain the caret of the editor.
77
- Show source positions for CommonMark in Markdown AST view.
88
- Reordered items in "Insert" menu and toolbar.
9+
- Formatting toolbar items (bold, italic, etc) are highlighted
10+
if the caret in the editor is at formatted text.
911

1012

1113
## 0.6

src/main/java/org/markdownwriterfx/FileEditor.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import javafx.beans.property.ObjectProperty;
3838
import javafx.beans.property.ReadOnlyBooleanProperty;
3939
import javafx.beans.property.ReadOnlyBooleanWrapper;
40+
import javafx.beans.property.ReadOnlyObjectProperty;
4041
import javafx.beans.property.SimpleBooleanProperty;
4142
import javafx.beans.property.SimpleObjectProperty;
4243
import javafx.beans.value.ChangeListener;
@@ -120,6 +121,10 @@ MarkdownEditorPane getEditor() {
120121
return markdownEditorPane;
121122
}
122123

124+
// 'editor' property
125+
private final ObjectProperty<MarkdownEditorPane> editor = new SimpleObjectProperty<>();
126+
ReadOnlyObjectProperty<MarkdownEditorPane> editorProperty() { return editor; }
127+
123128
// 'path' property
124129
private final ObjectProperty<Path> path = new SimpleObjectProperty<>();
125130
Path getPath() { return path.get(); }
@@ -229,6 +234,9 @@ private void activated() {
229234

230235
updatePreviewType();
231236
markdownEditorPane.requestFocus();
237+
238+
// update 'editor' property
239+
editor.set(markdownEditorPane);
232240
}
233241

234242
void load() {

src/main/java/org/markdownwriterfx/MainWindow.java

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import javafx.beans.binding.BooleanBinding;
3535
import javafx.beans.property.BooleanProperty;
3636
import javafx.beans.property.SimpleBooleanProperty;
37+
import javafx.beans.value.ChangeListener;
3738
import javafx.beans.value.ObservableBooleanValue;
3839
import javafx.event.Event;
3940
import javafx.scene.Node;
@@ -305,19 +306,19 @@ private Node createMenuBarAndToolBar() {
305306
editUndoAction,
306307
editRedoAction,
307308
null,
308-
insertBoldAction,
309-
insertItalicAction,
310-
insertCodeAction,
309+
new Action(insertBoldAction, createActiveEditBooleanProperty(SmartEdit::boldProperty)),
310+
new Action(insertItalicAction, createActiveEditBooleanProperty(SmartEdit::italicProperty)),
311+
new Action(insertCodeAction, createActiveEditBooleanProperty(SmartEdit::codeProperty)),
311312
null,
312-
insertLinkAction,
313-
insertImageAction,
313+
new Action(insertLinkAction, createActiveEditBooleanProperty(SmartEdit::linkProperty)),
314+
new Action(insertImageAction, createActiveEditBooleanProperty(SmartEdit::imageProperty)),
314315
null,
315-
insertUnorderedListAction,
316-
insertOrderedListAction,
317-
insertBlockquoteAction,
318-
insertFencedCodeBlockAction,
316+
new Action(insertUnorderedListAction, createActiveEditBooleanProperty(SmartEdit::unorderedListProperty)),
317+
new Action(insertOrderedListAction, createActiveEditBooleanProperty(SmartEdit::orderedListProperty)),
318+
new Action(insertBlockquoteAction, createActiveEditBooleanProperty(SmartEdit::blockquoteProperty)),
319+
new Action(insertFencedCodeBlockAction, createActiveEditBooleanProperty(SmartEdit::fencedCodeProperty)),
319320
null,
320-
insertHeader1Action);
321+
new Action(insertHeader1Action, createActiveEditBooleanProperty(SmartEdit::headerProperty)));
321322

322323
// horizontal spacer
323324
Region spacer = new Region();
@@ -391,6 +392,39 @@ private BooleanProperty createActiveBooleanProperty(Function<FileEditor, Observa
391392
return b;
392393
}
393394

395+
/**
396+
* Creates a boolean property that is bound to another boolean value
397+
* of the active editor's SmartEdit.
398+
*/
399+
private BooleanProperty createActiveEditBooleanProperty(Function<SmartEdit, ObservableBooleanValue> func) {
400+
BooleanProperty b = new SimpleBooleanProperty() {
401+
@Override
402+
public void set(boolean newValue) {
403+
// invoked when the user invokes an action
404+
// do not try to change SmartEdit properties because this
405+
// would throw a "bound value cannot be set" exception
406+
}
407+
};
408+
409+
ChangeListener<? super FileEditor> listener = (observable, oldFileEditor, newFileEditor) -> {
410+
b.unbind();
411+
if (newFileEditor != null) {
412+
if (newFileEditor.getEditor() != null)
413+
b.bind(func.apply(newFileEditor.getEditor().getSmartEdit()));
414+
else {
415+
newFileEditor.editorProperty().addListener((ob, o, n) -> {
416+
b.bind(func.apply(n.getSmartEdit()));
417+
});
418+
}
419+
} else
420+
b.set(false);
421+
};
422+
FileEditor fileEditor = fileEditorTabPane.getActiveFileEditor();
423+
listener.changed(null, null, fileEditor);
424+
fileEditorTabPane.activeFileEditorProperty().addListener(listener);
425+
return b;
426+
}
427+
394428
Alert createAlert(AlertType alertType, String title,
395429
String contentTextFormat, Object... contentTextArgs)
396430
{

src/main/java/org/markdownwriterfx/editor/SmartEdit.java

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
import java.util.List;
3939
import java.util.regex.Matcher;
4040
import java.util.regex.Pattern;
41+
import javafx.application.Platform;
42+
import javafx.beans.property.BooleanProperty;
43+
import javafx.beans.property.SimpleBooleanProperty;
4144
import javafx.scene.control.IndexRange;
4245
import javafx.scene.input.KeyEvent;
4346
import org.apache.commons.lang3.StringUtils;
@@ -49,18 +52,27 @@
4952
import org.markdownwriterfx.options.Options;
5053
import org.markdownwriterfx.util.Utils;
5154
import com.vladsch.flexmark.ast.AutoLink;
55+
import com.vladsch.flexmark.ast.Block;
56+
import com.vladsch.flexmark.ast.BlockQuote;
57+
import com.vladsch.flexmark.ast.BulletListItem;
5258
import com.vladsch.flexmark.ast.Code;
59+
import com.vladsch.flexmark.ast.ContentNode;
5360
import com.vladsch.flexmark.ast.DelimitedNode;
5461
import com.vladsch.flexmark.ast.Emphasis;
62+
import com.vladsch.flexmark.ast.FencedCodeBlock;
5563
import com.vladsch.flexmark.ast.Heading;
5664
import com.vladsch.flexmark.ast.Image;
65+
import com.vladsch.flexmark.ast.ImageRef;
5766
import com.vladsch.flexmark.ast.Link;
5867
import com.vladsch.flexmark.ast.LinkNode;
68+
import com.vladsch.flexmark.ast.LinkRef;
5969
import com.vladsch.flexmark.ast.ListBlock;
6070
import com.vladsch.flexmark.ast.ListItem;
6171
import com.vladsch.flexmark.ast.MailLink;
6272
import com.vladsch.flexmark.ast.Node;
6373
import com.vladsch.flexmark.ast.NodeVisitor;
74+
import com.vladsch.flexmark.ast.OrderedListItem;
75+
import com.vladsch.flexmark.ast.Paragraph;
6476
import com.vladsch.flexmark.ast.StrongEmphasis;
6577
import com.vladsch.flexmark.ext.gfm.strikethrough.Strikethrough;
6678
import com.vladsch.flexmark.util.sequence.BasedSequence;
@@ -100,8 +112,100 @@ public class SmartEdit
100112

101113
// textArea.selectionProperty().addListener((ob, o, n) ->
102114
// System.out.println(findNodes(n.getStart(), n.getEnd(), (s, e, node) -> true, true)));
115+
116+
editor.markdownASTProperty().addListener((ob, o, n) -> updateStateProperties());
117+
textArea.selectionProperty().addListener((ob, o, n) -> updateStateProperties());
103118
}
104119

120+
//---- properties ---------------------------------------------------------
121+
122+
private boolean updateStatePropertiesRunLaterPending;
123+
private void updateStateProperties() {
124+
// avoid too many (and useless) runLater() invocations
125+
if (updateStatePropertiesRunLaterPending)
126+
return;
127+
updateStatePropertiesRunLaterPending = true;
128+
129+
Platform.runLater(() -> {
130+
updateStatePropertiesRunLaterPending = false;
131+
132+
List<Node> nodesAtSelection = findNodesAtSelection((s, e, n) -> true, true);
133+
134+
boolean bold = false;
135+
boolean italic = false;
136+
boolean code = false;
137+
boolean link = false;
138+
boolean image = false;
139+
boolean unorderedList = false;
140+
boolean orderedList = false;
141+
boolean blockquote = false;
142+
boolean fencedCode = false;
143+
boolean header = false;
144+
for (Node node : nodesAtSelection) {
145+
if (!bold && node instanceof StrongEmphasis)
146+
bold = true;
147+
else if (!italic && node instanceof Emphasis)
148+
italic = true;
149+
else if (!code && node instanceof Code)
150+
code = true;
151+
else if (!link && (node instanceof Link || node instanceof LinkRef))
152+
link = true;
153+
else if (!image && (node instanceof Image || node instanceof ImageRef))
154+
image = true;
155+
else if (!unorderedList && node instanceof BulletListItem)
156+
unorderedList = true;
157+
else if (!orderedList && node instanceof OrderedListItem)
158+
orderedList = true;
159+
else if (!blockquote && node instanceof BlockQuote)
160+
blockquote = true;
161+
else if (!fencedCode && node instanceof FencedCodeBlock)
162+
fencedCode = true;
163+
else if (!header && node instanceof Heading)
164+
header = true;
165+
}
166+
this.bold.set(bold);
167+
this.italic.set(italic);
168+
this.code.set(code);
169+
this.link.set(link);
170+
this.image.set(image);
171+
this.unorderedList.set(unorderedList);
172+
this.orderedList.set(orderedList);
173+
this.blockquote.set(blockquote);
174+
this.fencedCode.set(fencedCode);
175+
this.header.set(header);
176+
});
177+
}
178+
179+
private final BooleanProperty bold = new SimpleBooleanProperty();
180+
public BooleanProperty boldProperty() { return bold; }
181+
182+
private final BooleanProperty italic = new SimpleBooleanProperty();
183+
public BooleanProperty italicProperty() { return italic; }
184+
185+
private final BooleanProperty code = new SimpleBooleanProperty();
186+
public BooleanProperty codeProperty() { return code; }
187+
188+
private final BooleanProperty link = new SimpleBooleanProperty();
189+
public BooleanProperty linkProperty() { return link; }
190+
191+
private final BooleanProperty image = new SimpleBooleanProperty();
192+
public BooleanProperty imageProperty() { return image; }
193+
194+
private final BooleanProperty unorderedList = new SimpleBooleanProperty();
195+
public BooleanProperty unorderedListProperty() { return unorderedList; }
196+
197+
private final BooleanProperty orderedList = new SimpleBooleanProperty();
198+
public BooleanProperty orderedListProperty() { return orderedList; }
199+
200+
private final BooleanProperty blockquote = new SimpleBooleanProperty();
201+
public BooleanProperty blockquoteProperty() { return blockquote; }
202+
203+
private final BooleanProperty fencedCode = new SimpleBooleanProperty();
204+
public BooleanProperty fencedCodeProperty() { return fencedCode; }
205+
206+
private final BooleanProperty header = new SimpleBooleanProperty();
207+
public BooleanProperty headerProperty() { return header; }
208+
105209
//---- enter -------------------------------------------------------------
106210

107211
private void enterPressed(KeyEvent e) {

src/main/java/org/markdownwriterfx/util/Action.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,13 @@ public Action(String text, String accelerator, GlyphIcons icon,
7171
this.disable = disable;
7272
this.selected = selected;
7373
}
74+
75+
public Action(Action action, BooleanProperty selected) {
76+
this.text = action.text;
77+
this.accelerator = action.accelerator;
78+
this.icon = action.icon;
79+
this.action = action.action;
80+
this.disable = action.disable;
81+
this.selected = selected;
82+
}
7483
}

0 commit comments

Comments
 (0)