package bluej.utility.javafx;

import bluej.Config;
import javafx.beans.binding.BooleanExpression;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.MenuItem;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;

import threadchecker.OnThread;
import threadchecker.Tag;

import java.util.Objects;


| An FX Abstract Action to replace the Swing Action class | | @author Neil Brown | @OnThread(Tag.FXPlatform) public abstract class FXAbstractAction { private String name; private boolean hasMenuItem = false; private final BooleanProperty unavailable = new SimpleBooleanProperty(false); private final BooleanProperty disabled = new SimpleBooleanProperty(false); protected final ObjectProperty<KeyCombination> accelerator; private final Node buttonGraphic; protected FXAbstractAction(String name) { this(name, (KeyCombination)null); } protected FXAbstractAction(String name, KeyCombination accelerator) { this.name = name; this.accelerator = new SimpleObjectProperty<>(accelerator); this.buttonGraphic = null; } protected FXAbstractAction(String name, Node buttonGraphic) { this.name = name; this.accelerator = new SimpleObjectProperty<>(null); this.buttonGraphic = buttonGraphic; } protected FXAbstractAction(String name, Image buttonImage) { this(name, new ImageView(buttonImage)); } public abstract void actionPerformed(boolean viaContextMenu); public void bindEnabled(BooleanExpression enabled) { if (enabled != null) disabled.bind(enabled.not()); } public void setEnabled(boolean enabled) { if (disabled.isBound()) disabled.unbind(); disabled.set(!enabled); } public boolean isDisabled() { return disabled.get(); }
| There's two ways in which actions become disabled. One is that their inherent | state in the editor changes, e.g. no undo if you haven't made any changes. | The other is that they become what we call unavailable, which happens when | the documentation view is showing, for example. So their GUI enabled status | is actually the conjunction of being enabled and available. | public void setAvailable(boolean available) { unavailable.set(!available); } public String getName() { return name; } public KeyCombination getAccelerator() { return accelerator.get(); } public Button makeButton() { Button button = new Button(name); button.disableProperty().bind(disabled.or(unavailable)); button.setOnAction(e -> actionPerformed(false)); if (buttonGraphic != null) button.setGraphic(buttonGraphic); return button; }
| Note: calling this method indicates that the item will have | a menu item with the accelerator available for use. Actions with a menu item | don't set a separate entry in the key map. So don't call this | unless you're actually going to have the menu item available on the menu. | public MenuItem makeMenuItem() { MenuItem menuItem = new MenuItem(name); prepareMenuItem(menuItem); return menuItem; } private void prepareMenuItem(MenuItem menuItem) { setMenuActionAndDisable(menuItem, false); boolean cmdPlusMinusOnMac = Config.isMacOS() && accelerator.get() != null && (accelerator.get().equals(new KeyCodeCombination(KeyCode.EQUALS, KeyCombination.SHORTCUT_DOWN)) || accelerator.get().equals(new KeyCodeCombination(KeyCode.MINUS, KeyCombination.SHORTCUT_DOWN)) || accelerator.get().equals(new KeyCodeCombination(KeyCode.EQUALS, KeyCombination.META_DOWN)) || accelerator.get().equals(new KeyCodeCombination(KeyCode.MINUS, KeyCombination.META_DOWN))); if (!cmdPlusMinusOnMac) { menuItem.acceleratorProperty().bind(accelerator); hasMenuItem = true; } }
| Makes a MenuItem which will run this action, but without an accelerator. | public MenuItem makeContextMenuItem() { MenuItem menuItem = new MenuItem(name); setMenuActionAndDisable(menuItem, true); return menuItem; } private void setMenuActionAndDisable(MenuItem menuItem, boolean contextMenu) { menuItem.disableProperty().bind(disabled.or(unavailable)); menuItem.setOnAction(e -> actionPerformed(true)); } public String toString() { return name; }
/*public Category getCategory() | |{} return category; | |} @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; FXAbstractAction that = (FXAbstractAction) o; return name.equals(that.name); } @Override public int hashCode() { return name.hashCode(); }
| Determines whether this action has a menu item which has been created, and which has the given | shortcut as an accelerator (compared using .equals method). We don't check if the menu item | is actually visible, or enabled, etc, that's up to the caller. | @param shortcut | @return | public boolean hasMenuItemWithAccelerator(KeyCombination shortcut) { return hasMenuItem && Objects.equals(accelerator.get(), shortcut); }
| Changes the name of the action. | @param name the new name to be assigned | public void setName(String name) { this.name = name; } }
top, use, map, abstract class FXAbstractAction

.   FXAbstractAction
.   FXAbstractAction
.   FXAbstractAction
.   FXAbstractAction
.   actionPerformed
.   bindEnabled
.   setEnabled
.   isDisabled
.   setAvailable
.   getName
.   getAccelerator
.   makeButton
.   makeMenuItem
.   prepareMenuItem
.   makeContextMenuItem
.   setMenuActionAndDisable
.   toString
.   equals
.   hashCode
.   hasMenuItemWithAccelerator
.   setName




218 neLoCode + 22 LoComm