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

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

Go to download

A plugin for Speedment that generates enum classes for every column that is the enum type.

The newest version!
/*
 *
 * Copyright (c) 2006-2020, 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 static com.speedment.runtime.config.util.DocumentUtil.ancestor;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.CompletableFuture.supplyAsync;
import static java.util.stream.Collectors.joining;
import static javafx.application.Platform.runLater;
import static javafx.scene.layout.Region.USE_PREF_SIZE;

import com.speedment.common.injector.Injector;
import com.speedment.common.injector.annotation.Inject;
import com.speedment.common.json.Json;
import com.speedment.common.logger.Logger;
import com.speedment.common.logger.LoggerManager;
import com.speedment.runtime.config.Column;
import com.speedment.runtime.config.Schema;
import com.speedment.runtime.config.Table;
import com.speedment.runtime.config.trait.HasName;
import com.speedment.runtime.config.trait.HasParent;
import com.speedment.runtime.core.component.PasswordComponent;
import com.speedment.runtime.core.component.ProjectComponent;
import com.speedment.runtime.core.db.DbmsMetadataHandler;
import com.speedment.runtime.core.internal.component.sql.SqlStreamSupplierComponentImpl;
import com.speedment.runtime.core.util.ProgressMeasure;
import com.speedment.tool.config.DbmsProperty;
import com.speedment.tool.config.trait.HasEnumConstantsProperty;
import com.speedment.tool.config.trait.HasTypeMapperProperty;
import com.speedment.tool.core.component.UserInterfaceComponent;
import com.speedment.tool.core.exception.SpeedmentToolException;
import com.speedment.tool.core.resource.FontAwesome;
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.layout.HBox;
import javafx.scene.layout.VBox;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Stream;

/**
 * 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 3.0.0 */ public final class AddRemoveStringItem & HasName> extends AbstractLabelTooltipItem { private static final Logger LOGGER = LoggerManager.getLogger(AddRemoveStringItem.class); private final DOC column; private final ObservableList strings; private final ObservableBooleanValue enabled; @SuppressWarnings("FieldCanBeLocal") private final StringProperty cache; private static final String DEFAULT_FIELD = "ENUM_CONSTANT_"; private static final double SPACING = 10.0; private static final int LIST_HEIGHT = 200; @Inject public ProjectComponent projects; @Inject public DbmsMetadataHandler metadata; @Inject public PasswordComponent passwords; @Inject public UserInterfaceComponent ui; @Inject public Injector injector; //////////////////////////////////////////////////////////////////////////// // Constructor // //////////////////////////////////////////////////////////////////////////// AddRemoveStringItem( final DOC column, final String label, final StringProperty value, final String tooltip, final 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.column = requireNonNull(column); 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() { final 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), populateButton(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(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", FontAwesome.TIMES.view()); 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", FontAwesome.PLUS.view()); button.setOnAction(e -> { final int newIndex = listView.getItems().size(); final Set set = new HashSet<>(strings); 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 Button populateButton(final ListView listView) { final Button button = new Button("Populate", FontAwesome.DATABASE.view()); button.setOnAction(e -> { final Column col = column.getMappedColumn(); final DbmsProperty dbms = ancestor(col, DbmsProperty.class).get(); final String dbmsName = dbms.getName(); final String schemaName = ancestor(col, Schema.class).get().getName(); final String tableName = col.getParentOrThrow().getName(); final String columnName = col.getName(); final ProgressMeasure progress = ProgressMeasure.create(); if (!passwords.get(dbmsName).isPresent()) { ui.showPasswordDialog(dbms); } final char[] password = passwords.get(dbmsName).orElseThrow(() -> new SpeedmentToolException( "A password is required to populate enum constants field!" ) ); final CompletableFuture task = supplyAsync(() -> { try { // Hack to create a Manager for reading a single column from // the database. LOGGER.info("Creating Temporary Speedment..."); progress.setProgress(0.2); final Injector inj = injector.newBuilder() .withComponent(TempApplicationMetadata.class) .withComponent(SqlStreamSupplierComponentImpl.class) .withParam("temp.json", Json.toJson(dbms.getParentOrThrow().getData())) .withParam("temp.dbms", dbmsName) .withParam("temp.schema", schemaName) .withParam("temp.table", tableName) .withParam("temp.column", columnName) .withComponent(SingleColumnManager.class) .withComponent(SingleColumnSqlAdapter.class) .beforeInitialized(PasswordComponent.class, passw -> { LOGGER.info("Installing Password..."); passw.put(dbmsName, password); }) .build(); LOGGER.info("Temporary Speedment built. Streaming..."); progress.setProgress(0.4); final String constants = inj.getOrThrow(SingleColumnManager.class).stream() .distinct().sorted() .collect(joining(",")); LOGGER.info("Streaming complete!"); // Run in UI thread: runLater(() -> { column.enumConstantsProperty().setValue(constants); setValue(constants); progress.setProgress(1.0); }); return true; } catch (final InstantiationException ex) { LOGGER.error(ex); return false; } }).handleAsync((res, ex) -> { if (ex != null) { LOGGER.error(ex); return false; } progress.setProgress(1.0); return true; }); ui.showProgressDialog("Populating Enum Constants", progress, task); }); return button; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy