All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.rpgframework.jfx.SelectionControlTwoColumnSkin Maven / Gradle / Ivy

package de.rpgframework.jfx;

import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.util.List;

import de.rpgframework.genericrpg.chargen.ComplexDataItemController;
import de.rpgframework.genericrpg.chargen.OperationResult;
import de.rpgframework.genericrpg.data.Choice;
import de.rpgframework.genericrpg.data.DataItem;
import de.rpgframework.genericrpg.data.DataItemValue;
import javafx.application.Platform;
import javafx.scene.Node;
import javafx.scene.SnapshotParameters;
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.VBox;
import javafx.util.Callback;

/**
 * @author prelle
 *
 */
public class SelectionControlTwoColumnSkin> extends SkinBase> {
	
	private final static Logger logger = RPGFrameworkJavaFX.logger;

	private ListView listPossible;
	private ListView listSelected;
	
	private Label lblAvailable;
	private Label lblSelected;
	
	private Callback, ListCell> cfAvailable;
	private Callback, ListCell> cfSelected;
	
	private HBox columns;
	
	//-------------------------------------------------------------------
	protected SelectionControlTwoColumnSkin(SelectionControllerNode control) {
		super(control);
		initComponents();
		initLayout();
		initInteractivity();
	}

	//-------------------------------------------------------------------
	private void initComponents() {
		cfAvailable = new Callback, ListCell>() {
			public ListCell call(ListView param) {
				ListCell cell = (getSkinnable().getAvailableCellFactory()!=null)?getSkinnable().getAvailableCellFactory().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().getSelectedCellFactory()!=null)?getSkinnable().getSelectedCellFactory().call(param):createDefaultCellImpl();
				cell.setOnMouseClicked(ev -> mouseClickedSelected(cell, ev));
				cell.setOnDragDetected(ev -> dragDetectedSelected(cell, ev));
				return cell;
			}
		};
		
		listPossible = new ListView();
		listPossible.setCellFactory(cfAvailable);
		listPossible.itemsProperty().bind(getSkinnable().availableProperty());
		
		listSelected = new ListView();
		listSelected.setCellFactory(cfSelected);
		listSelected.itemsProperty().bind(getSkinnable().selectedProperty());
		
		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();
		
		if (getSkinnable().getShowHeadings()) {
			VBox col1 = new VBox(lblAvailable, listPossible);
			VBox col2 = new VBox(lblSelected, listSelected);
			col1.setStyle("-fx-spacing: 1em");
			col2.setStyle("-fx-spacing: 1em");
			VBox.setVgrow(listPossible, Priority.ALWAYS);
			VBox.setVgrow(listSelected, Priority.ALWAYS);
			columns.getChildren().addAll(col1, col2);
		} else {
			columns.getChildren().addAll(listPossible, listSelected);
		}
	}

	//-------------------------------------------------------------------
	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));
		
		listPossible.getSelectionModel().selectedItemProperty().addListener( (ov,o,n) -> getSkinnable().setShowHelpFor(n));
		listSelected.getSelectionModel().selectedItemProperty().addListener( (ov,o,n) -> getSkinnable().setShowHelpFor((n!=null)?n.getModifyable():null));
		listPossible.setOnDragOver(ev -> dragOverAvailable(ev));
		listSelected.setOnDragOver(ev -> dragOverSelected(ev));
		listPossible.setOnDragDropped(ev -> dragDroppedAvailable(ev));
		listSelected.setOnDragDropped(ev -> dragDroppedSelected(ev));
	}

    //-------------------------------------------------------------------
    private static  ListCell createDefaultCellImpl() {
        return new ListCell() {
            @Override public void updateItem(T 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(T toSelect) {
    	logger.log(Level.DEBUG, "userSelects("+toSelect+")");
    	ComplexDataItemController ctrl = getSkinnable().getController();
    	if (ctrl.canBeSelected(toSelect).get()) {
    		// Is there a need for a selection
    		if (!ctrl.getChoicesToDecide(toSelect).isEmpty()) {
    			// Yes, user must choose
    			List options = ctrl.getChoicesToDecide(toSelect);
    			logger.log(Level.DEBUG, "called getOptions");
    			if (getSkinnable().getOptionCallback()!=null) {
    				Platform.runLater( () -> {
    					logger.log(Level.ERROR, "TODO;call getOptionCallback");
//    					Object choice = getSkinnable().getOptionCallback().apply(toSelect, options);
//    					if (choice!=null) {
//    						logger.log(Level.DEBUG, "call select(option)");
//    						ctrl.select(toSelect, choice);
//    					}
    				});
    			}
    		} else {
    			// No
    			logger.log(Level.DEBUG, "call select before: "+getSkinnable().getSelected());
    		   	OperationResult res = ctrl.select(toSelect);
    		   	logger.log(Level.DEBUG, "call select after: "+getSkinnable().getSelected());
    		   	if (res.isPresent()) {
        		   	V selected = res.get();
        		   	if (selected!=null) {
        		   		listSelected.getItems().add(selected);
//        		   		listSelected.getItems().setAll(getSkinnable().getSelected());
        		   	}
    		   		
    		   	}
    		}
    	} else {
    		logger.log(Level.DEBUG, "can not be Selected("+toSelect+")");
    	}
    }

	//-------------------------------------------------------------------
	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) {
		T data = cell.getItem();
		if (data==null)
			return;
		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.getTypeString()+":"+data.getId();
        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
            T toSelect = null;
            for (T tmp : getSkinnable().getController().getAvailable()) {
            	String cmp = tmp.getTypeString()+":"+tmp.getId();
            	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
            T toSelect = null;
            for (T tmp : getSkinnable().getController().getAvailable()) {
            	String cmp = tmp.getTypeString()+":"+tmp.getId();
            	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();
	}


}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy