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

com.speedment.plugins.enums.internal.ui.AddRemoveStringItem Maven / Gradle / Ivy

/**
 *
 * Copyright (c) 2006-2016, Speedment, Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); You may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.speedment.plugins.enums.internal.ui;

import com.speedment.common.logger.Logger;
import com.speedment.common.logger.LoggerManager;
import com.speedment.tool.propertyeditor.item.AbstractLabelTooltipItem;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableBooleanValue;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.TextFieldListCell;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.util.StringConverter;

import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toSet;
import static javafx.application.Platform.runLater;
import static javafx.scene.layout.Region.USE_PREF_SIZE;

/**
 * Item for generating a comma-separated string.
 * 

* We parse what values an enum should be able to take from a string, where * each element is separated by a comma. This editor item allows the user * to easily edit such a string. * * @author Simon Jonasson * @since 1.0.0 */ public final class AddRemoveStringItem extends AbstractLabelTooltipItem { //*********************************************************** // VARIABLES //*********************************************************** private final static Logger LOGGER = LoggerManager.getLogger(AddRemoveStringItem.class); private final ObservableList strings; private final ObservableBooleanValue enabled; @SuppressWarnings("FieldCanBeLocal") private final StringProperty cache; private final String DEFAULT_FIELD = "ENUM_CONSTANT_"; private final double SPACING = 10.0; private final int LIST_HEIGHT = 200; //*********************************************************** // CONSTRUCTOR //*********************************************************** public AddRemoveStringItem( String label, StringProperty value, String tooltip, ObservableBooleanValue enableThis) { super(label, tooltip, NO_DECORATOR); final String currentValue = value.get(); if (currentValue == null) { this.strings = FXCollections.observableArrayList(); } else { this.strings = FXCollections.observableArrayList( Stream.of(currentValue.split(",")) .filter(s -> !s.isEmpty()) .toArray(String[]::new) ); } this.enabled = enableThis; this.cache = new SimpleStringProperty(); this.strings.addListener((ListChangeListener.Change c) -> { @SuppressWarnings("unchecked") final List list = (List) c.getList(); value.setValue(getFormatedString(list)); }); } //*********************************************************** // PUBLIC //*********************************************************** @Override public Node createLabel() { Node node = super.createLabel(); hideShowBehaviour(node); return node; } @Override protected Node createUndecoratedEditor() { final VBox container = new VBox(); final ListView listView = new ListView<>(strings); listView.setCellFactory(view -> new EnumCell(strings)); listView.setEditable(true); listView.setMaxHeight(USE_PREF_SIZE); listView.setPrefHeight(LIST_HEIGHT); final HBox controls = new HBox(SPACING); controls.setAlignment(Pos.CENTER); controls.getChildren().addAll(addButton(listView), removeButton(listView)); container.setSpacing(SPACING); container.getChildren().addAll(listView, controls); hideShowBehaviour(container); return container; } //*********************************************************** // PRIVATE //*********************************************************** /** * Removes any empty substrings and makes sure the entire string is either * {@code null} or non-empty. * * @return the formatted string */ private String getFormatedString(List newValue) { final String formated = newValue.stream() .filter(v -> !v.isEmpty()) .collect(Collectors.joining(",")); if (formated == null || formated.isEmpty()) { return null; } else { return formated; } } private void setValue(String value) { if (value == null) { strings.clear(); } else { strings.setAll(value.split(",")); } } private void hideShowBehaviour(Node node){ node.visibleProperty().bind(enabled); node.managedProperty().bind(enabled); node.disableProperty().bind(Bindings.not(enabled)); } private Button removeButton(final ListView listView) { final Button button = new Button("Remove Selected"); button.setOnAction(e -> { final int selectedIdx = listView.getSelectionModel().getSelectedIndex(); if (selectedIdx != -1 && listView.getItems().size() > 1) { final int newSelectedIdx = (selectedIdx == listView.getItems().size() - 1) ? selectedIdx - 1 : selectedIdx; listView.getItems().remove(selectedIdx); listView.getSelectionModel().select(newSelectedIdx); } }); return button; } private Button addButton(final ListView listView) { final Button button = new Button("Add Item"); button.setOnAction(e -> { final int newIndex = listView.getItems().size(); final Set set = strings.stream().collect(toSet()); final AtomicInteger i = new AtomicInteger(0); while (!set.add(DEFAULT_FIELD + i.incrementAndGet())) {} listView.getItems().add(DEFAULT_FIELD + i.get()); listView.scrollTo(newIndex); listView.getSelectionModel().select(newIndex); /* There is a strange behavior in JavaFX if you try to start editing * a field on the same animation frame as another field lost focus. * * Therefore, we wait one animation cycle before setting the field * into the editing state */ runLater(() -> listView.edit(newIndex)); }); return button; } //*********************************************************** // PRIVATE CLASS : ENUM CELL //*********************************************************** private final static class EnumCell extends TextFieldListCell { private final ObservableList strings; private String labelString; private EnumCell(ObservableList strings) { super(); this.strings = requireNonNull(strings); setConverter(myConverter()); } @Override public void startEdit() { labelString = getText(); super.startEdit(); } private StringConverter myConverter() { return new StringConverter() { @Override public String toString(String value) { return (value != null) ? value : ""; } @Override public String fromString(String value) { // Avoid false positives (ie showing an error that we match ourselves) if (value.equalsIgnoreCase(labelString)) { return value; } else if (value.isEmpty()) { LOGGER.info("An enum field cannot be empty. Please remove the field instead."); return labelString; } // Make sure this is not a douplicate entry final AtomicBoolean douplicate = new AtomicBoolean(false); strings.stream() .filter(elem -> elem.equalsIgnoreCase(value)) .forEach(elem -> douplicate.set(true)); if (douplicate.get()){ LOGGER.info("Enum cannot contain the same constant twice"); return labelString; // Make sure this entry contains only legal characters } else if ( !value.matches("([\\w\\-\\_\\ ]+)")) { LOGGER.info("Enum should only contain letters, number, underscore and/or dashes"); return labelString; // Warn if it contains a space } else if (value.contains(" ")) { LOGGER.warn("Enum spaces will be converted to underscores in Java"); return value; } else { return value; } } }; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy