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

org.scenicview.view.tabs.details.GDetailPane Maven / Gradle / Ivy

The newest version!
/*
 * Scenic View,
 * Copyright (C) 2012 Jonathan Giles, Ander Ruiz, Amy Fowler
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.scenicview.view.tabs.details;

import javafx.beans.value.WritableValue;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
import javafx.scene.control.TitledPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import org.fxconnector.details.Detail;
import org.fxconnector.details.Detail.EditionType;
import org.fxconnector.details.DetailPaneType;
import org.scenicview.utils.Logger;
import org.scenicview.view.DisplayUtils;
import org.scenicview.view.ScenicViewGui;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;

public class GDetailPane extends TitledPane {

	private static final int LABEL_COLUMN = 0;
	private static final int VALUE_COLUMN = 1;

	public static final float FADE = .50f;
	public static DecimalFormat f = new DecimalFormat("0.0#");

	private static final Image EDIT_IMAGE = DisplayUtils.getUIImage("editclear.png");
	private static final Image LOCK_IMAGE = DisplayUtils.getUIImage("lock.png");

	static final String DETAIL_LABEL_STYLE = "detail-label";

	private final ScenicViewGui scenicView;

	public final DetailPaneType type;
	public final GridPane gridpane;
	static GDetail activeDetail;
	final List paneNodes = new ArrayList<>();
	final List details = new ArrayList<>();
	final Consumer loader;

	public GDetailPane(ScenicViewGui scenicView, final DetailPaneType type, final String name, final Consumer loader) {
		this.scenicView = scenicView;
		this.type = type;
		this.loader = loader;
		setText(name);
		getStyleClass().add("detail-pane");
		setManaged(false);
		setVisible(false);
		setExpanded(false);
		setMaxWidth(Double.MAX_VALUE);
		setId("title-label");
		setAlignment(Pos.CENTER_LEFT);

		gridpane = new GridPane();
		gridpane.getStyleClass().add("detail-grid");
		gridpane.setOnMousePressed(event -> {
			if (activeDetail != null)
				activeDetail.recover();
		});
		gridpane.setHgap(4);
		gridpane.setVgap(2);
		gridpane.setSnapToPixel(true);
		final ColumnConstraints colInfo = new ColumnConstraints(180);
		gridpane.getColumnConstraints().addAll(colInfo, new ColumnConstraints());
		setContent(gridpane);

	}

	protected GDetail addDetail(final String propertyName, final String labelText, final Node labelGraphic, final Node valueNode, final int row) {
		final Label label = new Label(labelText);
		if (labelGraphic != null) {
			label.setGraphic(labelGraphic);
			label.setContentDisplay(ContentDisplay.LEFT);
		}

		final GDetail detail = new GDetail(scenicView, label, valueNode);
		detail.setAPILoader(loader);
		GridPane.setConstraints(detail.label, LABEL_COLUMN, row);
		GridPane.setHalignment(detail.label, HPos.RIGHT);
		GridPane.setValignment(detail.label, VPos.TOP);
		detail.label.getStyleClass().add(DETAIL_LABEL_STYLE);

		if (valueNode instanceof Label) {
			final Group group = new Group(detail.valueLabel);
			GridPane.setConstraints(group, VALUE_COLUMN, row);
			GridPane.setHalignment(group, HPos.LEFT);
			GridPane.setValignment(group, VPos.TOP);
			detail.valueLabel.getStyleClass().add("detail-value");
			addToPane(detail.label, group);
		} else {
			// icky, but fine for now
			final Group group = new Group(detail.valueNode);
			GridPane.setConstraints(group, VALUE_COLUMN, row);
			GridPane.setHalignment(group, HPos.LEFT);
			GridPane.setValignment(group, VPos.TOP);
			addToPane(detail.label, group);
		}

		details.add(detail);
		return detail;
	}

	protected void clearPane() {
		gridpane.getChildren().clear();
		paneNodes.clear();
		details.clear();
	}

	protected void addToPane(final Node... nodes) {
		gridpane.getChildren().addAll(nodes);
		paneNodes.addAll(Arrays.asList(nodes));
	}

	private String currentFilter = null;

	public void filterProperties(final String text) {
		// if (currentFilter != null && currentFilter.equals(text)) {
		// return;
		// }
		currentFilter = text;

		/*
		 * Make this more clean
		 */
		gridpane.getChildren().clear();
		final List nodes = paneNodes;
		int row = 0;
		for (int i = 0; i < nodes.size(); i++) {

			final Label label = (Label) nodes.get(i++);
			boolean valid = text == null || text.equals("") || label.getText().toLowerCase().contains(text.toLowerCase());
			final Group g = (Group) nodes.get(i);
			final Node value = g.getChildren().get(0);

			if (!valid && value instanceof Label) {
				valid = ((Label) value).getText().toLowerCase().contains(text.toLowerCase());
			}

			if (valid && label.isVisible()) {
				GridPane.setConstraints(label, LABEL_COLUMN, row);
				GridPane.setConstraints(g, VALUE_COLUMN, row);
				gridpane.getChildren().addAll(label, g);
				row++;
			}
		}
	}

	@Override
	protected double computeMinWidth(final double height) {
		return prefWidth(height);
	}

	@Override
	protected double computeMinHeight(final double width) {
		return prefHeight(width);
	}

	public void updateDetails(final List details, final RemotePropertySetter setter) {
		clearPane();
		for (int i = 0; i < details.size(); i++) {
			final Detail d = details.get(i);
			Node labelGraphic;
			switch (d.getLabelType()) {
				case LAYOUT_BOUNDS -> {
					final Rectangle layoutBoundsIcon = new Rectangle(12, 12);
					layoutBoundsIcon.setFill(null);
					layoutBoundsIcon.setStroke(Color.GREEN);
					layoutBoundsIcon.setOpacity(.8);
					layoutBoundsIcon.getStrokeDashArray().addAll(3.0, 3.0);
					layoutBoundsIcon.setStrokeWidth(1);
					labelGraphic = layoutBoundsIcon;
				}
				case BOUNDS_PARENT -> {
					final Rectangle boundsInParentIcon = new Rectangle(12, 12);
					boundsInParentIcon.setFill(Color.YELLOW);
					boundsInParentIcon.setOpacity(.5);
					labelGraphic = boundsInParentIcon;
				}
				case BASELINE -> {
					final Group baselineIcon = new Group();
					final Line line = new Line(0, 8, 14, 8);
					line.setStroke(Color.RED);
					line.setOpacity(.75);
					line.setStrokeWidth(1);
					baselineIcon.getChildren().addAll(new Rectangle(10, 10, Color.TRANSPARENT), line);
					labelGraphic = baselineIcon;
				}
				default -> labelGraphic = null;
			}

			Node value = null;
			final boolean isEditingSupported = Detail.isEditionSupported(d.getEditionType());
			final boolean isPropertyBound = d.getEditionType() == EditionType.NONE_BOUND;
			final Node graphic = isEditingSupported ? new ImageView(GDetailPane.EDIT_IMAGE) :
					isPropertyBound ? new ImageView(GDetailPane.LOCK_IMAGE) :
							null;

			switch (d.getValueType()) {
				case NORMAL -> {
					final Label valueLabel = new Label();
					valueLabel.setGraphic(graphic);
					value = valueLabel;
				}
				case INSETS -> value = new InsetsDisplay();
				case CONSTRAINTS -> value = new ConstraintsDisplay();
				case GRID_CONSTRAINTS -> value = new GridConstraintDisplay();
				case COLOR -> {
					final Label valueLabel = new Label();
					Color c;
					try {
						c = Color.valueOf(d.getValue());
					} catch (IllegalArgumentException e) {
						Logger.print("Error for color: " + d.getValue());
						c = Color.BLACK;
					}
					Rectangle rect = new Rectangle(10, 10, c);
					HBox hbox = new HBox(5, graphic, rect);
					hbox.setAlignment(Pos.CENTER_LEFT);
					valueLabel.setGraphic(hbox);
					valueLabel.setText(d.getValue());
					value = valueLabel;
				}
			}

			final GDetail detail = addDetail(d.getProperty(), d.getLabel(), labelGraphic, value, i);
			doUpdateDetail(detail, d);
			detail.setSerializer(new WritableValue<>() {
				@Override
				public void setValue(final String value) {
					try {
						setter.set(d, value);
					} catch (final Exception e) {
						scenicView.setStatusText(Detail.STATUS_EXCEPTION + e.getMessage(), 10000);
					}
				}

				@Override
				public String getValue() {
					// TODO Auto-generated method stub
					return null;
				}
			});
		}
		filterProperties(currentFilter);
	}

	public void updateDetail(final Detail detail) {
		GDetail pane = null;
		for (GDetail gDetail : details) {
			if (gDetail.detail.equals(detail)) {
				pane = gDetail;
				break;
			}
		}
		if (pane != null) {
			doUpdateDetail(pane, detail);
			pane.updated();
			filterProperties(currentFilter);
		} else {
			Logger.print("Pane not found for detail:" + detail);
		}
	}

	private void doUpdateDetail(final GDetail detail, final Detail d) {
		detail.setDetail(d);
		detail.setIsDefault(d.isDefault());
		detail.setReason(d.getReason());
		detail.setValidItems(d.getValidItems());
		detail.setMinMax(d.getMinValue(), d.getMaxValue());
		detail.setEditionType(d.getEditionType());
		detail.setRealValue(d.getRealValue());
		detail.setValue(d.getValue());
	}

	public interface RemotePropertySetter {
		void set(Detail detail, String value);
	}

	@Override
	public String toString() {
		if (details.isEmpty()) {
			return "";
		}
		final StringBuilder sb = new StringBuilder();
		sb.append(type).append('\n');
		for (GDetail detail : details) {
			sb.append(detail).append('\n');
		}
		return sb.toString();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy