Dave Jarvis' Repositories

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

Infrastructure for hierarchical menu items

AuthorDaveJarvis <email>
Date2020-09-20 18:23:41 GMT-0700
Commit3ed1d0b414b3c7e19f3ffb37cc643e89632f4f9a
Parent330c48e
Delta202 lines added, 64 lines removed, 138-line increase
src/main/resources/com/keenwrite/messages.properties
Main.menu.file.save_as=Save _As
Main.menu.file.save_all=Save A_ll
+Main.menu.file.export=_Export
+Main.menu.file.export.html_svg=HTML and S_VG
+Main.menu.file.export.html_tex=HTML and _TeX
Main.menu.file.exit=E_xit
src/main/java/com/keenwrite/util/ActionBuilder.java
public Action build() {
- return new Action( mText, mAccelerator, mIcon, mAction, mDisable );
+ return new MenuAction( mText, mAccelerator, mIcon, mAction, mDisable );
}
}
src/main/java/com/keenwrite/util/ActionUtils.java
package com.keenwrite.util;
-import de.jensd.fx.glyphs.fontawesome.utils.FontAwesomeIconFactory;
import javafx.scene.Node;
-import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
-import javafx.scene.control.Separator;
-import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.ToolBar;
-import javafx.scene.control.Tooltip;
/**
public static MenuItem[] createMenuItems( final Action... actions ) {
- final MenuItem[] menuItems = new MenuItem[ actions.length ];
+ final var menuItems = new MenuItem[ actions.length ];
for( int i = 0; i < actions.length; i++ ) {
- menuItems[ i ] = (actions[ i ] == null)
- ? new SeparatorMenuItem()
- : createMenuItem( actions[ i ] );
+ menuItems[ i ] = actions[ i ].createMenuItem();
}
return menuItems;
- }
-
- public static MenuItem createMenuItem( final Action action ) {
- final MenuItem menuItem = new MenuItem( action.text );
-
- if( action.accelerator != null ) {
- menuItem.setAccelerator( action.accelerator );
- }
-
- if( action.icon != null ) {
- menuItem.setGraphic(
- FontAwesomeIconFactory.get().createIcon( action.icon ) );
- }
-
- menuItem.setOnAction( action.action );
-
- if( action.disable != null ) {
- menuItem.disableProperty().bind( action.disable );
- }
-
- menuItem.setMnemonicParsing( true );
-
- return menuItem;
}
public static ToolBar createToolBar( final Action... actions ) {
return new ToolBar( createToolBarButtons( actions ) );
}
public static Node[] createToolBarButtons( final Action... actions ) {
Node[] buttons = new Node[ actions.length ];
- for( int i = 0; i < actions.length; i++ ) {
- buttons[ i ] = (actions[ i ] != null)
- ? createToolBarButton( actions[ i ] )
- : new Separator();
- }
- return buttons;
- }
-
- public static Button createToolBarButton( final Action action ) {
- final Button button = new Button();
- button.setGraphic(
- FontAwesomeIconFactory
- .get()
- .createIcon( action.icon, "1.2em" ) );
-
- String tooltip = action.text;
-
- if( tooltip.endsWith( "..." ) ) {
- tooltip = tooltip.substring( 0, tooltip.length() - 3 );
- }
-
- if( action.accelerator != null ) {
- tooltip += " (" + action.accelerator.getDisplayText() + ')';
- }
-
- button.setTooltip( new Tooltip( tooltip ) );
- button.setFocusTraversable( false );
- button.setOnAction( action.action );
- if( action.disable != null ) {
- button.disableProperty().bind( action.disable );
+ for( int i = 0; i < actions.length; i++ ) {
+ buttons[ i ] = actions[ i ].createToolBarButton();
}
- return button;
+ return buttons;
}
}
src/main/java/com/keenwrite/util/MenuAction.java
+/*
+ * Copyright 2020 Karl Tauber and White Magic Software, Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.keenwrite.util;
+
+import de.jensd.fx.glyphs.GlyphIcons;
+import javafx.beans.value.ObservableBooleanValue;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.scene.control.Button;
+import javafx.scene.control.Menu;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.Tooltip;
+import javafx.scene.input.KeyCombination;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static de.jensd.fx.glyphs.fontawesome.utils.FontAwesomeIconFactory.get;
+import static javafx.scene.input.KeyCombination.valueOf;
+
+/**
+ * Defines actions the user can take by interacting with the GUI.
+ */
+public class MenuAction extends Action {
+ private final String mText;
+ private final KeyCombination mAccelerator;
+ private final GlyphIcons mIcon;
+ private final EventHandler<ActionEvent> mAction;
+ private final ObservableBooleanValue mDisabled;
+ private final List<Action> mSubActions = new ArrayList<>();
+
+ public MenuAction(
+ final String text,
+ final String accelerator,
+ final GlyphIcons icon,
+ final EventHandler<ActionEvent> action,
+ final ObservableBooleanValue disabled ) {
+
+ mText = text;
+ mAccelerator = accelerator == null ? null : valueOf( accelerator );
+ mIcon = icon;
+ mAction = action;
+ mDisabled = disabled;
+ }
+
+ @Override
+ public MenuItem createMenuItem() {
+ // This will either become a menu or a menu item, depending on whether
+ // sub-actions are defined.
+ final MenuItem menuItem;
+
+ if( mSubActions.isEmpty() ) {
+ // Regular menu item has no sub-menus.
+ menuItem = new MenuItem( mText );
+ }
+ else {
+ // Sub-actions are translated into sub-menu items beneath this action.
+ final var submenu = new Menu( mText );
+
+ for( final var action : mSubActions ) {
+ // Recursive call that creates a sub-menu hierarchy.
+ submenu.getItems().add( action.createMenuItem() );
+ }
+
+ menuItem = submenu;
+ }
+
+ if( mAccelerator != null ) {
+ menuItem.setAccelerator( mAccelerator );
+ }
+
+ if( mIcon != null ) {
+ menuItem.setGraphic( get().createIcon( mIcon ) );
+ }
+
+ if( mAction != null ) {
+ menuItem.setOnAction( mAction );
+ }
+
+ if( mDisabled != null ) {
+ menuItem.disableProperty().bind( mDisabled );
+ }
+
+ menuItem.setMnemonicParsing( true );
+
+ return menuItem;
+ }
+
+ @Override
+ public Button createToolBarButton() {
+ final Button button = new Button();
+ button.setGraphic(
+ get().createIcon( mIcon, "1.2em" ) );
+
+ String tooltip = mText;
+
+ if( tooltip.endsWith( "..." ) ) {
+ tooltip = tooltip.substring( 0, tooltip.length() - 3 );
+ }
+
+ if( mAccelerator != null ) {
+ tooltip += " (" + mAccelerator.getDisplayText() + ')';
+ }
+
+ button.setTooltip( new Tooltip( tooltip ) );
+ button.setFocusTraversable( false );
+ button.setOnAction( mAction );
+
+ if( mDisabled != null ) {
+ button.disableProperty().bind( mDisabled );
+ }
+
+ return button;
+ }
+
+ @Override
+ public void addSubActions( final Action... action ) {
+ mSubActions.addAll( List.of( action ) );
+ }
+}
src/main/java/com/keenwrite/util/SeparatorAction.java
+/*
+ * Copyright 2020 White Magic Software, Ltd.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * o Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * o Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.keenwrite.util;
+
+import javafx.scene.Node;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.Separator;
+import javafx.scene.control.SeparatorMenuItem;
+
+/**
+ * Represents a menu bar action that has no operation, acting as a placeholder
+ * for line separators.
+ */
+public class SeparatorAction extends Action {
+ @Override
+ public MenuItem createMenuItem() {
+ return new SeparatorMenuItem();
+ }
+
+ @Override
+ public Node createToolBarButton() {
+ return new Separator();
+ }
+}