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

org.diirt.javafx.graphene.ConfigurationDialog Maven / Gradle / Ivy

/**
 * Copyright (C) 2010-18 diirt developers. See COPYRIGHT.TXT
 * All rights reserved. Use is subject to license terms. See LICENSE.TXT
 */
package org.diirt.javafx.graphene;

import java.util.ArrayList;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Priority;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.WindowEvent;
import org.diirt.graphene.InterpolationScheme;
import org.diirt.graphene.NumberColorMap;

/**
 * Allows the user to configure the properties of a graph (e.g. the x column of
 * a bubble graph, or the interpolation scheme of a line graph).
 * 

* To create a custom ConfigurationDialog, in the containing class, * list out what properties the user may configure. In most cases, the containing * class will be of type BaseGraphApp, and the supported property types are *

    *
  • String *
  • Boolean *
  • InterpolationScheme *
  • NumberColorMap *
* *

* Then find the appropriate method and add that property to the configuration * dialog. For some properties such as the interpolation scheme and number * color mapping, the user cannot choose anything s/he wants. Therefore, a list * of allowed properties is also required *

* For example, to allow a NumberColorMap property to be configured, * simply use the code *

 * 
 * Property< NumberColorMap > p = ...
 * NumberColorMap[] allowedNumberColorMaps = ...
 * configurationDialog.addNumberColorMapListProperty( p );
 * 
 * 
*

* * @author mjchao */ public class ConfigurationDialog extends Stage { /** * Contains the configuration field in which the user's current configurations * for a property are stored, and remembers the last saved configuration for * this property * * @param the type of data used for this configuration (e.g. string, boolean) */ private class ConfigurationData< T > { final public ConfigurationField< T > field; final public Property< T > lastSavedProperty; public ConfigurationData( ConfigurationField< T > f , Property< T > p ) { this.field = f; this.lastSavedProperty = p; } } /** * stores the data for all the properties in this configuration dialog */ private final ArrayList< ConfigurationData > configurationData = new ArrayList< ConfigurationData >(); /** * panel containing everything in this dialog */ private final BorderPane pnlMain = new BorderPane(); /** * panel containing the configuration fields in which the user enters * his/her choices */ private final GridPane pnlConfigurations = new GridPane(); /** * panel providing options for the user to save the current configurations * or cancel and revert to the previously saved configuration */ private final GridPane pnlSaveCancel = new GridPane(); /** * Creates a default configuration dialog with no configurations available */ public ConfigurationDialog() { this.initStyle( StageStyle.UTILITY ); this.setTitle( "Configure..." ); Scene s = new Scene( pnlMain ); pnlMain.setCenter( pnlConfigurations ); pnlMain.setPadding( new Insets( 5 , 5 , 5 , 5 ) ); //we assume that there will only ever be 2 columns: 1 to label the //property and 1 for the input method for that property this.pnlConfigurations.getColumnConstraints().addAll( new ColumnConstraints() , new ColumnConstraints() ); this.pnlConfigurations.getColumnConstraints().get( 1 ).setHgrow( Priority.ALWAYS ); this.pnlConfigurations.setVgap( 5 ); this.pnlConfigurations.setHgap( 5 ); FlowPane pnlBottom = new FlowPane(); pnlBottom.setAlignment( Pos.CENTER_RIGHT ); pnlBottom.getChildren().add( pnlSaveCancel ); pnlMain.setBottom( pnlBottom ); Button cmdConfigure = new Button( "Accept" ); cmdConfigure.setMinSize( 0 , 0 ); cmdConfigure.setMaxSize( Double.MAX_VALUE , Double.MAX_VALUE ); cmdConfigure.setOnAction( new EventHandler< ActionEvent >() { @Override public void handle(ActionEvent event) { saveChanges(); ConfigurationDialog.this.hide(); } }); Button cmdRevert = new Button( "Revert" ); cmdRevert.setMinSize( 0 , 0 ); cmdRevert.setMaxSize( Double.MAX_VALUE , Double.MAX_VALUE ); cmdRevert.setOnAction( new EventHandler< ActionEvent >() { @Override public void handle(ActionEvent event) { cancelChanges(); } }); Button cmdCancel = new Button( "Cancel" ); cmdCancel.setMinSize( 0 , 0 ); cmdCancel.setMaxSize( Double.MAX_VALUE , Double.MAX_VALUE ); cmdCancel.setOnAction( new EventHandler< ActionEvent >() { @Override public void handle( ActionEvent event ) { ConfigurationDialog.this.hide(); } }); this.setOnHidden( new EventHandler< WindowEvent >() { @Override public void handle(WindowEvent event) { cancelChanges(); } }); pnlSaveCancel.setHgap( 5 ); pnlSaveCancel.setVgap( 5 ); pnlSaveCancel.add( cmdConfigure , 0 , 0 ); pnlSaveCancel.add( cmdRevert , 1 , 0 ); pnlSaveCancel.add( cmdCancel , 2 , 0 ); pnlSaveCancel.getColumnConstraints().addAll( new ColumnConstraints() , new ColumnConstraints() , new ColumnConstraints() ); pnlSaveCancel.getColumnConstraints().get( 0 ).setHgrow( Priority.ALWAYS ); pnlSaveCancel.getColumnConstraints().get( 0 ).setHalignment( HPos.RIGHT ); pnlSaveCancel.getColumnConstraints().get( 1 ).setHgrow( Priority.ALWAYS ); pnlSaveCancel.getColumnConstraints().get( 1 ).setHalignment( HPos.RIGHT ); pnlSaveCancel.getColumnConstraints().get( 2 ).setHgrow( Priority.ALWAYS ); pnlSaveCancel.getColumnConstraints().get( 2 ).setHalignment( HPos.RIGHT ); pnlSaveCancel.setPadding( new Insets( 5 , 0 , 0 , 0 ) ); this.setScene( s ); } /** * Adds a property field to this configuration dialog. The graphical components * are displayed in the dialog box, and the configuration data will be modified * as the user changes the property. * * @param graphicalComponents the graphical components of which the property field consists * @param data the data related to the property field to be added */ private void addPropertyField( Node[] graphicalComponents , ConfigurationData data ) { for ( int i=0 ; i p , InterpolationScheme[] allowedInterpolations ) { InterpolationSchemeField newField = new InterpolationSchemeField( name , p , allowedInterpolations ); ConfigurationData data = new ConfigurationData( newField , new SimpleObjectProperty< InterpolationScheme >( p.getValue() ) ); addPropertyField( newField.getComponents() , data ); } /** * Adds the given number-color mapping property as something the user may * configure. In the dialog, this property will have a label containing the * name of the property and a combobox which the user can use to modify * this property. * * @param name the textual name of the property (e.g. "X Column") * @param p the number-color mapping property that the user may modify * @param allowedMappings the list of allowed number-color mappings */ public void addNumberColorMapListProperty( String name , Property< NumberColorMap > p , NumberColorMap[] allowedMappings ) { NumberColorMapField newField = new NumberColorMapField( name , p , allowedMappings ); ConfigurationData data = new ConfigurationData( newField , new SimpleObjectProperty< NumberColorMap >( p.getValue() ) ); addPropertyField( newField.getComponents() , data ); } /** * Saves the current configuration state so that the user may revert to it * later if necessary */ public void saveChanges() { for ( ConfigurationData d : this.configurationData ) { d.lastSavedProperty.setValue( d.field.getValue() ); } } /** * Discards the user's current configurations and reverts to the previous * saved configuration state */ public void cancelChanges() { loadSaved(); } /** * Loads the previously saved configuration state, discarding any * configurations that may currently exist. */ public void loadSaved() { for ( ConfigurationData d : this.configurationData ) { d.field.setValue( d.lastSavedProperty.getValue() ); } } /** * Opens this configuration dialog. */ public void open() { this.show(); this.toFront(); this.sizeToScene(); this.loadSaved(); } /** * Provides the user with the ability to configure one property. *

* Note: Fields may only have 2 components: a label and some sort of input method, e.g. * a combobox or text field. This is necessary to maintain an appealing look * for the dialog box * * @param the type of property this field allows the user to modify */ private class ConfigurationField< T > extends FlowPane { /** * the property the user is allowed to modify */ final private Property< T > m_property; /** * Creates a configuration field for the given property. * * @param property the property the user may configure * @param onPropertyChanged what to do if the user changes the property */ public ConfigurationField( Property< T > property ) { this.m_property = property; } public Property< T > property() { return this.m_property; } public void setValue( T value ) { this.m_property.setValue( value ); } public T getValue() { return this.m_property.getValue(); } public Node[] getComponents() { return new Node[]{}; } } /** * Creates a default name label for a property. This simply takes the given * property name, and appends ": " to it. * * @param propertyName the name of a property * @return a label with the default name display */ private static Label defaultNameLabel( String propertyName ) { return new Label( propertyName + ":" ); } /** * Provides the user with the ability to configure a string property */ private class StringField extends ConfigurationField< String > { /** * shows the name of the property */ final private Label lblName; /** * shows the value of the property, and allows the user to change * the value of the property by typing something in this text field */ final private TextField txtValue; /** * Creates a default string field that allows the user to configure * a text-based property * * @param name the textual name of the property (e.g. "X Column") * @param p the property the user can configure */ public StringField( String name , StringProperty p ) { super( p ); this.lblName = defaultNameLabel( name ); this.txtValue = new TextField( " " ); this.txtValue.textProperty().bindBidirectional( p ); this.txtValue.setText( p.getValue() ); } @Override public Node[] getComponents() { return new Node[]{ this.lblName , this.txtValue }; } } /** * Provides the user with the ability to configure a boolean property */ private class BooleanField extends ConfigurationField< Boolean > { /** * shows the name of the property */ final private Label lblName; /** * allows the user to configure the property by toggling it with this * check box */ final private CheckBox chkValue; /** * Creates a default boolean field that allows the user to configure * a boolean property * * @param name the textual name of the property (e.g. "X Column") * @param p the property the user can configure */ public BooleanField( String name , BooleanProperty p ) { super( p ); this.lblName = defaultNameLabel( name ); this.chkValue = new CheckBox(); this.chkValue.selectedProperty().bindBidirectional( p ); this.chkValue.setSelected( p.getValue() ); this.chkValue.setMaxWidth( Double.MAX_VALUE ); } @Override public Node[] getComponents() { return new Node[]{ this.lblName , this.chkValue }; } } /** * Provides the user with the ability to select an InterpolationScheme */ private class InterpolationSchemeField extends ConfigurationField< InterpolationScheme > { final private Label lblName; final private ComboBox< InterpolationScheme > cboInterpolations; /** * Creates an InterpolationSchemeField that allows the user to configure * an interpolation scheme property by selecting an interpolation scheme * from a list of allowed interpolation schemes. * * @param name the textual name of the property (e.g. "X Column") * @param p the interpolation scheme property the user can configure * @param interpolationSchemes the list of allowed interpolation schemes, * which must be nonempty * @throws IllegalArgumentException if the list of allowed interpolation * schemes is empty */ public InterpolationSchemeField( String name , Property p , InterpolationScheme[] interpolationSchemes ) { super( p ); if ( interpolationSchemes.length == 0 ) { throw new IllegalArgumentException( "Must have at least 1 allowed interpolation scheme." ); } this.lblName = defaultNameLabel( name ); this.cboInterpolations = new ComboBox< InterpolationScheme >(); this.cboInterpolations.getItems().addAll( interpolationSchemes ); this.cboInterpolations.valueProperty().bindBidirectional( p ); this.cboInterpolations.setValue( p.getValue() ); this.cboInterpolations.setMaxWidth( Double.MAX_VALUE ); } @Override public Node[] getComponents() { return new Node[]{this.lblName , this.cboInterpolations}; } } /** * Provides the user with the ability to select a NumberColorMap property */ private class NumberColorMapField extends ConfigurationField< NumberColorMap > { final private Label lblName; final private ComboBox< NumberColorMap > cboColorMaps = new ComboBox< NumberColorMap >(); /** * Creates a NumberColorMapField that allows the user to configure a * number-color mapping by selecting one from a list of allowed * mappings * * @param name the textual name of the property (e.g. "X Column") * @param p the property the user can configure * @param maps the allowed mappings the user can select * @throws IllegalArugmentException if there are no allowed mapping from which the user can select */ public NumberColorMapField( String name , Property< NumberColorMap > p , NumberColorMap[] maps ) { super( p ); if ( maps.length == 0 ) { throw new IllegalArgumentException( "Must have at least 1 allowed number-color mapping" ); } this.lblName = defaultNameLabel( name ); this.cboColorMaps.getItems().addAll( maps ); this.cboColorMaps.valueProperty().bindBidirectional( p ); this.cboColorMaps.setValue( p.getValue() ); this.cboColorMaps.setMaxWidth( Double.MAX_VALUE ); } @Override public Node[] getComponents() { return new Node[]{ this.lblName , this.cboColorMaps }; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy