Dave Jarvis' Repositories

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

Add editing to key-value table cells

Author DaveJarvis <email>
Date 2021-12-20 01:12:04 GMT-0800
Commit bcb2625ec18772c0530718eb13c046627dc5cbc9
Parent fb3891b
Delta 157 lines added, 91 lines removed, 66-line increase
src/main/java/com/keenwrite/preferences/SimpleTableControl.java
import com.dlsc.preferencesfx.formsfx.view.controls.SimpleControl;
import javafx.beans.property.SimpleObjectProperty;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Insets;
+import javafx.scene.control.Button;
+import javafx.scene.control.ButtonBar;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
+import javafx.scene.control.cell.TextFieldTableCell;
+import javafx.scene.layout.VBox;
import java.util.AbstractMap.SimpleEntry;
+import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
+import static com.keenwrite.ui.fonts.IconFactory.createGraphic;
import static java.util.Arrays.asList;
import static javafx.collections.FXCollections.observableArrayList;
+import static javafx.scene.control.SelectionMode.MULTIPLE;
public class SimpleTableControl<K, V>
- extends SimpleControl<MapField<K, V>, TableView<Entry<K, V>>> {
+ extends SimpleControl<MapField<K, V>, VBox> {
+
+ private static long sCounter;
/**
super.initializeParts();
- final var table = new TableView<>( observableArrayList( mMap.entrySet() ) );
+ final var model = observableArrayList( mMap.entrySet() );
+ final var table = new TableView<>( model );
table.setEditable( true );
table.getColumns().addAll(
asList(
createEditableColumnKey( table ),
createEditableColumnValue( table )
)
);
+ table.getSelectionModel().setSelectionMode( MULTIPLE );
- super.node = table;
+ final var buttons = new ButtonBar();
+ buttons.getButtons().addAll(
+ createButton(
+ "Add", "PLUS",
+ event -> {
+ sCounter++;
+
+ final var k = (K) ("key" + sCounter);
+ final var v = (V) ("value" + sCounter);
+
+ model.add( new SimpleEntry<>( k, v ) );
+ }
+ ),
+
+ createButton(
+ "Delete", "TRASH",
+ event -> {
+ final var selectionModel = table.getSelectionModel();
+ final var selection = selectionModel.getSelectedItems();
+
+ if( selection != null && !selection.isEmpty() ) {
+ final var items = table.getItems();
+ final var rows = new ArrayList<>( selection );
+ rows.forEach( items::remove );
+
+ selectionModel.clearSelection();
+ }
+ }
+ )
+ );
+
+ final var vbox = new VBox();
+ vbox.setSpacing( 5 );
+ vbox.setPadding( new Insets( 10, 0, 0, 10 ) );
+ vbox.getChildren().addAll( table, buttons );
+
+ super.node = vbox;
+ }
+
+ private Button createButton(
+ final String label,
+ final String graphic,
+ final EventHandler<ActionEvent> handler ) {
+ assert label != null;
+ assert !label.isBlank();
+ assert graphic != null;
+ assert !graphic.isBlank();
+ assert handler != null;
+
+ final var button = new Button( label, createGraphic( graphic ) );
+ button.setOnAction( handler );
+ return button;
}
)
);
+ column.setCellFactory( callback -> new TextFieldTableCell<>() );
return column;
src/main/java/com/keenwrite/ui/actions/Action.java
private final List<MenuAction> mSubActions = new ArrayList<>();
+ /**
+ * Provides a fluent interface around constructing actions so that duplication
+ * can be avoided.
+ */
+ public static class Builder {
+ private String mText;
+ private String mAccelerator;
+ private String mIcon;
+ private EventHandler<ActionEvent> mHandler;
+
+ /**
+ * Sets the text, icon, and accelerator for a given action identifier.
+ * See the messages properties file for details.
+ *
+ * @param id The identifier to look up in the properties file.
+ * @return An instance of {@link Builder} that can be built into an
+ * instance of {@link Action}.
+ */
+ public Builder setId( final String id ) {
+ final var prefix = ACTION_PREFIX + id + ".";
+ final var text = prefix + "text";
+ final var icon = prefix + "icon";
+ final var accelerator = prefix + "accelerator";
+ final var builder = setText( text ).setIcon( icon );
+
+ return Messages.containsKey( accelerator )
+ ? builder.setAccelerator( Messages.get( accelerator ) )
+ : builder;
+ }
+
+ /**
+ * Sets the action text based on a resource bundle key.
+ *
+ * @param key The key to look up in the {@link Messages}.
+ * @return The corresponding value, or the key name if none found.
+ */
+ private Builder setText( final String key ) {
+ mText = Messages.get( key, key );
+ return this;
+ }
+
+ private Builder setAccelerator( final String accelerator ) {
+ mAccelerator = accelerator;
+ return this;
+ }
+
+ private Builder setIcon( final String iconKey ) {
+ assert iconKey != null;
+
+ // If there's no icon associated with the icon key name, don't attempt
+ // to create a graphic for the icon, because it won't exist.
+ final var iconName = Messages.get( iconKey );
+ mIcon = iconKey.equals( iconName ) ? "" : iconName;
+
+ return this;
+ }
+
+ public Builder setHandler( final EventHandler<ActionEvent> handler ) {
+ mHandler = handler;
+ return this;
+ }
+
+ public Action build() {
+ return new Action( mText, mAccelerator, mIcon, mHandler );
+ }
+ }
+
+ /**
+ * TODO: Reuse the {@link GenericBuilder}.
+ *
+ * @return The {@link Builder} for an instance of {@link Action}.
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ private static Button createIconButton( final String icon ) {
+ return new Button( null, createGraphic( icon ) );
+ }
+
public Action(
final String text,
@Override
public Button createToolBarNode() {
- final var button = createIconButton();
+ final var button = createIconButton( mIcon );
var tooltip = mText;
return button;
- }
-
- private Button createIconButton() {
- return new Button( null, createGraphic( mIcon ) );
}
mSubActions.addAll( List.of( action ) );
return this;
- }
-
- /**
- * TODO: Reuse the {@link GenericBuilder}.
- *
- * @return The {@link Builder} for an instance of {@link Action}.
- */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Provides a fluent interface around constructing actions so that duplication
- * can be avoided.
- */
- public static class Builder {
- private String mText;
- private String mAccelerator;
- private String mIcon;
- private EventHandler<ActionEvent> mHandler;
-
- /**
- * Sets the text, icon, and accelerator for a given action identifier.
- * See the messages properties file for details.
- *
- * @param id The identifier to look up in the properties file.
- * @return An instance of {@link Builder} that can be built into an
- * instance of {@link Action}.
- */
- public Builder setId( final String id ) {
- final var prefix = ACTION_PREFIX + id + ".";
- final var text = prefix + "text";
- final var icon = prefix + "icon";
- final var accelerator = prefix + "accelerator";
- final var builder = setText( text ).setIcon( icon );
-
- return Messages.containsKey( accelerator )
- ? builder.setAccelerator( Messages.get( accelerator ) )
- : builder;
- }
-
- /**
- * Sets the action text based on a resource bundle key.
- *
- * @param key The key to look up in the {@link Messages}.
- * @return The corresponding value, or the key name if none found.
- */
- private Builder setText( final String key ) {
- mText = Messages.get( key, key );
- return this;
- }
-
- private Builder setAccelerator( final String accelerator ) {
- mAccelerator = accelerator;
- return this;
- }
-
- private Builder setIcon( final String iconKey ) {
- assert iconKey != null;
-
- // If there's no icon associated with the icon key name, don't attempt
- // to create a graphic for the icon, because it won't exist.
- final var iconName = Messages.get( iconKey );
- mIcon = iconKey.equals( iconName ) ? "" : iconName;
-
- return this;
- }
-
- public Builder setHandler( final EventHandler<ActionEvent> handler ) {
- mHandler = handler;
- return this;
- }
-
- public Action build() {
- return new Action( mText, mAccelerator, mIcon, mHandler );
- }
}
}
src/main/java/com/keenwrite/ui/fonts/IconFactory.java
/**
- * Prevent instantiation. Use the {@link #createGraphic(String)} method to
- * create an icon for display.
- */
- private IconFactory() {}
-
- /**
* Create a {@link Node} representation for the given icon name.
*
return createGraphic( valueOf( icon.toUpperCase() ) );
}
+
+ /**
+ * Prevent instantiation. Use the {@link #createGraphic(String)} method to
+ * create an icon for display.
+ */
+ private IconFactory() {}
}
src/main/resources/com/keenwrite/messages.properties
workspace.document.meta=Document Metadata
-workspace.document.meta.desc=Key-value pairs where values may contain variable references (e.g., '{{'book.title'}}').
+workspace.document.meta.desc=Key-value pairs; values may contain variable references (e.g., '{{'book.title'}}').
workspace.document.meta.title=Pairs