Introduction

The graphics view not only supports editing activities but also rows. If a row gets edited the entire row will be flipped around and additional controls will become visible on the "back" of the row. If the back of the row requires more space (height) than the front of the row then the height will be automatically adjusted. The following table lists the methods that are related to row editing:

Method Description
void startRowEditing(R row);

Initiates the row editing sequence on the given row. The back of the row will become visible and expose controls to change row settings.

void stopRowEditing();
void stopRowEditing(R row);
Stops the row editing of all rows or just the given row. The front of the row will become visible again.
ObjectProperty<RowEditingMode> rowEditingModeProperty();
void setRowEditingMode(RowEditingMode);
RowEditingMode getRowEditingMode();
Stores, sets, and retrieves the row edit mode. The enum GraphicsBase.RowEditingMode is used to determine whether the user will be able to edit rows at all, one row at a time, or multiple rows at the same time.
ObservableList<R> getRowsEditing();
An observable list of all rows that are currently being edited (their back is shown).
BooleanProperty animateRowEditor();
void setAnimateRowEditor(boolean);
boolean isAnimateRowEditor();
Stores, sets, and retrieves a flag that is used to signal whether the exposure of the row back will be immediate or animated.

Row Editor Factory

The row editor factory is used to create the controls for a given row at the moment when the user requests that the row will be edited. The factory is a callback method that gets called with a GraphicsBase.RowEditorParameter object. This parameter object stores some fields that can be useful for creating the editor controls and also a method for stopping the row editing.

Method Description
GraphicsBase getGraphics();
Returns a reference to the graphics view where the editing will occure.
R getRow();

Returns the row for which the row editor will be created.

void stopEditing();

A convenience method for the row editor controls that can be used to signal that the user is done editing the row. This method will usually get invoked by some kind of close button in the editor UI:

A row editor factory might look like this:

Row Editor Example
public class MyRowEditorFactory implements 
					Callback<RowEditorParameter<R>, Node> {
 
	public Node call(RowEditorParameter<R> param) {
		VBox box = new VBox();
 
		/*
		 * Bind the text property of the textfield to the name
		 * property of the row. This allows us to change the name
		 * of the row.
		 */
		TextField nameField = new TextField();
		Bindings.bindBidirectional(param.getRow().nameProperty(), nameField.textProperty());
 
		/*
		 * A close button to invoke the stopEditing() method
		 * on the parameter object.
		 */
		Button closeButton = new Button("Close");
		closeButton.setOnAction(evt -> param.stopEditing());
		box.getChildren().addAll(nameField, closeButton);
 
		/*
		 * Return the vbox node.
		 */
		return box;
	}
}

Row editors can be registered like this:

Row Editor Registration
GraphicsBase<?> graphics = ganttChart.getGraphics();
graphics.setRowEditorFactory(new MyRowEditorFactory());

Row Controls Factory

To trigger row editing the user interface needs to provide some kind of controls. This can be done in many ways, for example by the help of a context menu on a row. Another way is to use the built-in support for so-called "row controls". These controls appear / disappear every time the mouse cursor enters / exists a row. They are created by a callback implementation. This callback receives a parameter object of type GraphicsBase.RowControlsParameter. The following table lists the fields of this type.

Field Description
graphics The graphics view for which the callback gets invoked.
row The row for which controls will be created.

Example 1

A possible implementation of this callback can look like this:

Row Controls Factory
public class MyRowControlsFactory extends StackPane 
		implements Callback<RowControlsParameter, Node> {
	
	private Button button;
 
	public MyRowControlsFactory() {
 
		/*
		 * Important: let mouse events pass through.
		 */
		setMouseTransparent(true);
		button = new Button("Press Me");
		getChildren().add(button);
	}
 
	/*
	 * Reuse the button. Simply exchange the action that will
	 * happen when the user presses on it.
	 */
	public Node call(RowControlsParameter param) {
 		button.setOnAction(evt -> 
			System.out.println("Pressed on row " + 
					param.getRow().getName());
		return this;
	}
}

Please take notice that this factory is a Node object and returns itself every time the call() method gets invoked. Only the action of the button gets replaced with each inocation. This makes perfect sense as row controls are always only shown for one row at a time (as opposed to row editors where several of them can be in use at the same time).

 

The callback can be registered like this:

Row Controls Factory Registration
GraphicsBase<?> graphics = ganttChart.getGraphics();
graphics.setRowControlsFactory(new MyRowControlsFactory());

Example 2

The following is the code of the RowControls class in the FlexGanttFX "Extras" project. It adds a simple "Edit" button to the row. When clicked it will show the row editor controls on the back on the row.

RowControls.java
 /**
 * Copyright (C) 2014 Dirk Lemmermann Software & Consulting (dlsc.com) 
 * 
 * This file is part of FlexGanttFX.
 */
package com.flexganttfx.extras;


import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.util.Callback;
import com.flexganttfx.model.Row;
import com.flexganttfx.view.graphics.GraphicsBase.RowControlsParameter;

public class RowControls<R extends Row<?, ?, ?>> extends HBox implements
		Callback<RowControlsParameter<R>, Node> {


	private Button editButton;

	public RowControls() {
		setPickOnBounds(false);
		setMinSize(0, 0);
		setAlignment(Pos.TOP_RIGHT);
		setFillHeight(true);
		editButton = new Button("EDIT");
		editButton.getStyleClass().add("row-controls-button");
		getChildren().add(editButton);
	}

	@Override
	public Node call(RowControlsParameter<R> param) {
		editButton.setOnAction(evt -> param.getGraphics().startRowEditing(
				param.getRow()));
		return this;
	}
}

The matching CSS for the button is defined like this:

RowControls Button CSS
/*
 * Row controls button are shown when the mouse hovers over a row that can be
 * edited (flipped around).
 */
.row-controls-button {
	-fx-padding: 5 9 7 7;
	-fx-background-insets: 0 4 2 2;
	-fx-background-color: rgba(0,0,0,.5);
	-fx-background-radius: 0;
	-fx-text-fill: white;
	-fx-font-size: 8;
	-fx-font-weight: bold;
}

.row-controls-button:hover,
.row-controls-button:focused {
	-fx-padding: 5 9 7 7;
	-fx-background-insets: 0 4 2 2;
	-fx-background-color: rgba(0,0,0,.6);
	-fx-background-radius: 0;
	-fx-text-fill: white;
	-fx-font-size: 8;
	-fx-font-weight: bold;
}

.row-controls-button:pressed,
.row-controls-button:selected {
	-fx-background-color: rgba(0,0,0,.7);
	-fx-background-radius: 0;
}