de.rpgframework.jfx.SelectedValuesControllerTwoColumnSkin Maven / Gradle / Ivy
package de.rpgframework.jfx;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import org.prelle.javafx.AlertManager;
import org.prelle.javafx.AlertType;
import org.prelle.javafx.CloseType;
import org.prelle.javafx.FlexibleApplication;
import org.prelle.javafx.ManagedDialog;
import org.prelle.javafx.ResponsiveControlManager;
import org.prelle.javafx.SymbolIcon;
import org.prelle.javafx.WindowMode;
import de.rpgframework.ResourceI18N;
import de.rpgframework.genericrpg.Possible;
import de.rpgframework.genericrpg.chargen.OperationResult;
import de.rpgframework.genericrpg.chargen.SelectedValueController;
import de.rpgframework.genericrpg.data.ComplexDataItemValue;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.SnapshotParameters;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SkinBase;
import javafx.scene.image.WritableImage;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.DragEvent;
import javafx.scene.input.Dragboard;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.TransferMode;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
/**
* @author prelle
*
*/
public class SelectedValuesControllerTwoColumnSkin> extends SkinBase> {
private final static Logger logger = RPGFrameworkJavaFX.logger;
private Button btnAdd,btnDel;
private ListView listPossible;
private ListView listSelected;
private HBox line1Select;
private Label lblAvailable;
private Label lblSelected;
private Label phAvailable;
private Label phSelected;
private Callback, ListCell> cfAvailable;
private Callback, ListCell> cfSelected;
private HBox columns;
private VBox col1, col2;
//-------------------------------------------------------------------
protected SelectedValuesControllerTwoColumnSkin(SelectedValuesControllerNode control) {
super(control);
initComponents();
initLayout();
initInteractivity();
setResponsiveMode(ResponsiveControlManager.getCurrentMode());
}
//-------------------------------------------------------------------
private void initComponents() {
btnAdd = new Button(null, new SymbolIcon("Add"));
btnDel = new Button(null, new SymbolIcon("Delete"));
btnDel.setDisable(true);
cfAvailable = new Callback, ListCell>() {
public ListCell call(ListView param) {
ListCell cell = (getSkinnable().getCellFactory()!=null)?getSkinnable().getCellFactory().call(param):createDefaultCellImpl();
cell.setOnMouseClicked(ev -> mouseClickedAvailable(cell, ev));
cell.setOnDragDetected(ev -> dragDetectedAvailable(cell, ev));
return cell;
}
};
cfSelected = new Callback, ListCell>() {
public ListCell call(ListView param) {
ListCell cell = (getSkinnable().getCellFactory()!=null)?getSkinnable().getCellFactory().call(param):createDefaultCellImpl();
cell.setOnMouseClicked(ev -> mouseClickedSelected(cell, ev));
cell.setOnDragDetected(ev -> dragDetectedSelected(cell, ev));
return cell;
}
};
phAvailable = new Label();
phAvailable.setWrapText(true);
phSelected = new Label();
phSelected.setWrapText(true);
phSelected.setStyle("-fx-background-color: -fx-second-background");
listPossible = new ListView();
listPossible.setCellFactory(cfAvailable);
listPossible.itemsProperty().bind(getSkinnable().availableProperty());
listPossible.setPlaceholder(phAvailable);
listPossible.setStyle("-fx-border-width: 1px; -fx-border-color: white; -fx-border-style:solid;");
listPossible.setMaxHeight(Double.MAX_VALUE);
listSelected = new ListView();
listSelected.setCellFactory(cfSelected);
listSelected.itemsProperty().bind(getSkinnable().selectedProperty());
listSelected.setPlaceholder(phSelected);
listSelected.setStyle("-fx-background-color: -fx-second-background;");
listSelected.setMaxHeight(Double.MAX_VALUE);
lblAvailable = new Label(" "+getSkinnable().getAvailableHeading());
lblSelected = new Label(" "+getSkinnable().getSelectedHeading());
lblAvailable.getStyleClass().addAll("text-small-subheader","list-heading");
lblSelected.getStyleClass().addAll("text-small-subheader","list-heading");
listPossible.setStyle(getSkinnable().getAvailableStyle());
listSelected.setStyle(getSkinnable().getSelectedStyle());
listPossible.setMaxHeight(Double.MAX_VALUE);
columns = new HBox();
columns.setStyle("-fx-spacing: 1em;");
getChildren().add(columns);
}
//-------------------------------------------------------------------
private void initLayout() {
columns.getChildren().clear();
Region buf = new Region();
buf.setMaxWidth(Double.MAX_VALUE);
line1Select = new HBox(buf,btnAdd,btnDel);
HBox.setHgrow(buf, Priority.ALWAYS);
if (getSkinnable().getSelectedListHead()!=null)
line1Select.getChildren().add(0,getSkinnable().getSelectedListHead());
col1 = new VBox(listPossible);
col2 = new VBox(line1Select,listSelected);
VBox.setVgrow(listPossible, Priority.ALWAYS);
VBox.setVgrow(listSelected, Priority.ALWAYS);
col1.setFillWidth(true);
col2.setStyle("-fx-margin: 0 1em 0 0");
// col1.setStyle("-fx-min-width: 23em");
// col1.setStyle("-fx-max-width: 25em");
// col2.setStyle("-fx-min-width: 22em");
// col2.setStyle("-fx-max-width: 23em");
// if (ResponsiveControlManager.getCurrentMode()==WindowMode.MINIMAL) {
// col2.setStyle("-fx-min-width: 20em");
// col2.setStyle("-fx-max-width: 23em");
// }
HBox.setHgrow(col1, Priority.ALWAYS);
HBox.setHgrow(col2, Priority.ALWAYS);
// VBox.setVgrow(listPossible, Priority.ALWAYS);
// VBox.setVgrow(listSelected, Priority.ALWAYS);
columns.getChildren().addAll(col1, col2);
columns.setFillHeight(true);
if (getSkinnable().getShowHeadings()) {
VBox.setMargin(lblAvailable, new Insets(0,0,20,0));
VBox.setMargin(lblSelected, new Insets(0,0,20,0));
col1.getChildren().add(0,lblAvailable);
col2.getChildren().add(0,lblSelected);
}
// if (getSkinnable().filterNodeProperty().get()!=null)
// col1.getChildren().add(col1.getChildren().size()-1, getSkinnable().getFilterNode());
}
//-------------------------------------------------------------------
private void initInteractivity() {
// getSkinnable().availableCellFactoryProperty().addListener( (ov,o,n) -> listPossible.setCellFactory(n));
// getSkinnable().selectedCellFactoryProperty().addListener( (ov,o,n) -> listSelected.setCellFactory(n));
getSkinnable().showHeadingsProperty().addListener( (ov,o,n) -> initLayout());
getSkinnable().availableHeadingProperty().addListener( (ov,o,n) -> lblAvailable.setText(" "+n));
getSkinnable().selectedHeadingProperty().addListener( (ov,o,n) -> lblSelected.setText(" "+n));
getSkinnable().availableStyleProperty().addListener( (ov,o,n) -> listPossible.setStyle(n));
getSkinnable().selectedStyleProperty().addListener( (ov,o,n) -> listSelected.setStyle(n));
// getSkinnable().filterNodeProperty().addListener( (ov,o,n) -> {
// if (o!=null) col1.getChildren().remove(o);
// if (n!=null) col1.getChildren().add(col1.getChildren().size()-1,n);
// });
getSkinnable().selectedListHeadProperty().addListener( (ov,o,n) -> {
if (o!=null) line1Select.getChildren().remove(o);
if (n!=null) line1Select.getChildren().add(0, n);
});
phAvailable.textProperty().bind(getSkinnable().availablePlaceholderProperty());
phSelected.textProperty().bind(getSkinnable().selectedPlaceholderProperty());
listPossible.getSelectionModel().selectedItemProperty().addListener( (ov,o,n) -> getSkinnable().setShowHelpFor(n));
listSelected.getSelectionModel().selectedItemProperty().addListener( (ov,o,n) -> {
btnDel.setDisable(n==null || !getSkinnable().getController().canBeDeselected(n).get());
getSkinnable().setShowHelpFor((n!=null)?n:null);
});
listPossible.setOnDragOver(ev -> dragOverAvailable(ev));
listSelected.setOnDragOver(ev -> dragOverSelected(ev));
listPossible.setOnDragDropped(ev -> dragDroppedAvailable(ev));
listSelected.setOnDragDropped(ev -> dragDroppedSelected(ev));
btnAdd.setOnAction(ev -> onAddClicked());
btnDel.setOnAction(ev -> onDeleteClicked(listSelected.getSelectionModel().getSelectedItem()));
}
//-------------------------------------------------------------------
private static ListCell createDefaultCellImpl() {
return new ListCell() {
@Override public void updateItem(V item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else if (item instanceof Node) {
setText(null);
Node currentNode = getGraphic();
Node newNode = (Node) item;
if (currentNode == null || ! currentNode.equals(newNode)) {
setGraphic(newNode);
}
} else {
/**
* This label is used if the item associated with this cell is to be
* represented as a String. While we will lazily instantiate it
* we never clear it, being more afraid of object churn than a minor
* "leak" (which will not become a "major" leak).
*/
setText(item == null ? "null" : item.toString());
setGraphic(null);
}
}
};
}
// -------------------------------------------------------------------
private void userSelects(V toSelect) {
logger.log(Level.DEBUG, "userSelects(" + toSelect + ")");
SelectedValueController ctrl = getSkinnable().getController();
Possible possible = ctrl.canBeSelected(toSelect);
logger.log(Level.DEBUG, "possible = "+possible);
if (possible.get()) {
// Is there a need for a selection
logger.log(Level.DEBUG, "ctrl = " + ctrl);
logger.log(Level.DEBUG, "call select(option)");
OperationResult res = ctrl.select(toSelect);
if (res.wasSuccessful()) {
logger.log(Level.INFO, "Selecting {0} was successful", toSelect);
} else {
logger.log(Level.WARNING, "Selecting {0} failed: {1}", toSelect, res.getError());
AlertManager.showAlertAndCall(javafx.scene.control.Alert.AlertType.ERROR, "Failed adding", res.getError());
}
} else {
logger.log(Level.DEBUG, "can not be Selected(" + toSelect + "): " + possible.getI18NKey());
FlexibleApplication.getInstance().showAlertAndCall(AlertType.NOTIFICATION, "Selection failed", possible.toString());
}
}
//-------------------------------------------------------------------
private void mouseClickedAvailable(ListCell cell, MouseEvent ev) {
if (ev.getClickCount()==2) {
userSelects(cell.getItem());
getSkinnable().refresh();
}
}
//-------------------------------------------------------------------
private void mouseClickedSelected(ListCell cell, MouseEvent ev) {
if (ev.getClickCount()==2) {
if (getSkinnable().getController().canBeDeselected((V)cell.getItem()).get()) {
getSkinnable().getController().deselect((V)cell.getItem());
}
}
}
//-------------------------------------------------------------------
protected void dragDetectedAvailable(ListCell cell, MouseEvent event) {
V data = cell.getItem();
if (data==null)
return;
logger.log(Level.DEBUG, "check: can be selected");
if (!getSkinnable().getController().canBeSelected(data).get())
return;
Node source = (Node) event.getSource();
/* drag was detected, start a drag-and-drop gesture*/
/* allow any transfer mode */
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
/* Put a string on a dragboard */
ClipboardContent content = new ClipboardContent();
String id = data.getResolved().getTypeString()+":"+data.getKey();
content.putString(id);
db.setContent(content);
/* Drag image */
WritableImage snapshot = source.snapshot(new SnapshotParameters(), null);
db.setDragView(snapshot);
event.consume();
}
//-------------------------------------------------------------------
protected void dragDetectedSelected(ListCell cell, MouseEvent event) {
V data = cell.getItem();
if (data==null)
return;
if (!getSkinnable().getController().canBeDeselected(data).get())
return;
Node source = (Node) event.getSource();
/* drag was detected, start a drag-and-drop gesture*/
/* allow any transfer mode */
Dragboard db = source.startDragAndDrop(TransferMode.ANY);
/* Put a string on a dragboard */
ClipboardContent content = new ClipboardContent();
String id = data.getModifyable().getTypeString()+":"+data.getModifyable().getId();
content.putString(id);
db.setContent(content);
/* Drag image */
WritableImage snapshot = source.snapshot(new SnapshotParameters(), null);
db.setDragView(snapshot);
event.consume();
}
//-------------------------------------------------------------------
private void dragOverSelected(DragEvent event) {
Node target = (Node) event.getSource();
if (event.getGestureSource() != target && event.getDragboard().hasString()) {
String enhanceID = event.getDragboard().getString();
// Find from available
V toSelect = null;
for (V tmp : getSkinnable().getController().getAvailable()) {
String cmp = tmp.getResolved().getTypeString()+":"+tmp.getKey();
if (enhanceID.equals(cmp)) {
toSelect = tmp;
break;
}
}
if (toSelect!=null && getSkinnable().getController().canBeSelected(toSelect).get()) {
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
}
}
//-------------------------------------------------------------------
private void dragDroppedSelected(DragEvent event) {
/* if there is a string data on dragboard, read it and use it */
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
String enhanceID = db.getString();
// Find from available
V toSelect = null;
for (V tmp : getSkinnable().getController().getAvailable()) {
String cmp = tmp.getResolved().getTypeString()+":"+tmp.getKey();
if (enhanceID.equals(cmp)) {
toSelect = tmp;
break;
}
}
if (toSelect!=null) {
userSelects(toSelect);
getSkinnable().refresh();
}
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
event.consume();
}
//-------------------------------------------------------------------
private void dragOverAvailable(DragEvent event) {
Node target = (Node) event.getSource();
if (event.getGestureSource() != target && event.getDragboard().hasString()) {
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
}
}
//-------------------------------------------------------------------
private void dragDroppedAvailable(DragEvent event) {
/* if there is a string data on dragboard, read it and use it */
Dragboard db = event.getDragboard();
boolean success = false;
if (db.hasString()) {
String enhanceID = db.getString();
// Find from available
V toSelect = null;
for (V tmp : getSkinnable().getController().getSelected()) {
String cmp = tmp.getModifyable().getTypeString()+":"+tmp.getModifyable().getId();
if (enhanceID.equals(cmp)) {
toSelect = tmp;
break;
}
}
if (toSelect!=null) {
getSkinnable().getController().deselect(toSelect);
getSkinnable().refresh();
}
}
/* let the source know whether the string was successfully
* transferred and used */
event.setDropCompleted(success);
event.consume();
}
//-------------------------------------------------------------------
public void setResponsiveMode(WindowMode value) {
logger.log(Level.TRACE,"setResponsiveMode({0})", value);
if (value==WindowMode.MINIMAL) {
// Column 1 should not be permanently visible
columns.getChildren().remove(col1);
col2.setStyle("-fx-min-width: 20em; -fx-max-width: 23em");
btnAdd.setVisible(true);
} else {
btnAdd.setVisible(false);
// Make column 1 visible if necessary
col2.setStyle("-fx-min-width: 23em");
if (!columns.getChildren().contains(col1)) {
columns.getChildren().add(0,col1);
}
}
columns.requestLayout();
}
//-------------------------------------------------------------------
private void onAddClicked() {
logger.log(Level.WARNING, "Add button clicked");
GenericDescriptionVBox descr = new GenericDescriptionVBox(getSkinnable().getRequirementResolver(), getSkinnable().getModificationResolver());
descr.setStyle("-fx-min-height: 5em");
VBox pane = new VBox(10,col1, descr);
VBox.setVgrow(col1, Priority.ALWAYS);
VBox.setVgrow(descr, Priority.SOMETIMES);
listPossible.getSelectionModel().selectedItemProperty().addListener( (ov,o,n) -> {
descr.setData(n);
});
ManagedDialog dialog = new ManagedDialog(
ResourceI18N.get(RPGFrameworkJFXConstants.UI, "label.selectOne"),
pane, CloseType.CANCEL, CloseType.OK);
CloseType closed = FlexibleApplication.getInstance().showAndWait(dialog);
logger.log(Level.WARNING, "Closed with "+closed);
if (closed==CloseType.OK) {
V selected = listPossible.getSelectionModel().getSelectedItem();
if (selected!=null) {
userSelects(selected);
}
}
}
//-------------------------------------------------------------------
private void onDeleteClicked(V selected) {
logger.log(Level.DEBUG, "Delete button clicked for "+selected);
boolean success = getSkinnable().getController().deselect(selected);
if (success) {
listSelected.getItems().remove(selected);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy