// Copyright (c) 2005, the JUNG Project and the Regents of the University of California All rights reserved. This // SPDX-FileCopyrightText: 2020 Roberto Posenato // // SPDX-License-Identifier: LGPL-3.0-or-later package it.univr.di.cstnu.visualization; import edu.uci.ics.jung.algorithms.layout.GraphElementAccessor; import edu.uci.ics.jung.algorithms.layout.Layout; import edu.uci.ics.jung.visualization.VisualizationViewer; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry; import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.univr.di.Debug; import it.univr.di.cstnu.graph.*; import it.univr.di.cstnu.graph.Edge.ConstraintType; import it.univr.di.cstnu.graph.TNGraph.NetworkType; import it.univr.di.labeledvalue.*; import it.univr.di.labeledvalue.Label; import it.univr.di.labeledvalue.ALabelAlphabet.ALetter; import org.netbeans.validation.api.builtin.stringvalidation.StringValidators; import org.netbeans.validation.api.ui.ValidationGroup; import org.netbeans.validation.api.ui.swing.ValidationPanel; import javax.swing.*; import java.awt.*; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.awt.geom.Point2D; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * Allows to edit vertex or edge attributes. * * @param vertex type * @param edge type * * @author Roberto Posenato. * @version $Rev$ */ @SuppressWarnings("DynamicRegexReplaceableByCompiledPattern") public class CSTNUGraphAttributeEditingMousePlugin extends edu.uci.ics.jung.visualization.control.LabelEditingGraphMousePlugin { /** * */ static final Logger LOG = Logger.getLogger(CSTNUGraphAttributeEditingMousePlugin.class.getName()); /** * The editor in which this plugin works. */ TNEditor cstnEditor; /** * Create an instance with default settings * * @param cstnEditor1 reference to the editor object (useful for finding some part of its panels). */ @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "EI_EXPOSE_REP2", justification = "For efficiency reason, it includes an external mutable object.") public CSTNUGraphAttributeEditingMousePlugin(TNEditor cstnEditor1) { //I use InputEvent.BUTTON1_DOWN_MASK instead of InputEvent.BUTTON1_MASK because InputEvent.BUTTON1_MASK is deprecated. //Then, I don't use it for detecting when mouse1 is clicked because getModifiersEx changed w.r.t. getModifiers although manuals says to use getModifiersEx! super(InputEvent.BUTTON1_DOWN_MASK); cstnEditor = cstnEditor1; } /** * General method to set up a dialog to edit the attributes of a vertex or of an edge. * * @param e the edge * @param viewerName the viewer name * @param g graph * * @return true if one attribute at least has been modified */ @SuppressWarnings({"unchecked", "null", "DataFlowIssue"}) @SuppressFBWarnings(value = "NP_NULL_PARAM_DEREF", justification = "It is a false positive.") private static boolean edgeAttributesEditor(final E e, final String viewerName, final TNGraph g) { // Edge has a name, a default value (label for this value is determined by the conjunction of labels of its end-points and a type). final boolean editorPanel = viewerName.equals(TNEditor.EDITOR_NAME); // Create a ValidationPanel - this is a panel that will show // any problem with the input at the bottom with an icon final ValidationPanel panel = new ValidationPanel(); /* * The layout is a grid of 3 columns. */ final JPanel jp = new JPanel(new GridLayout(0, 3)); panel.setInnerComponent(jp); final ValidationGroup group = panel.getValidationGroup(); // Name final JTextField name = new JTextField(e.getName()); JLabel jl = new JLabel("Name:"); jl.setLabelFor(name); jp.add(jl); jp.add(name); setConditionToEnable(name, viewerName, false); jp.add(new JLabel("RE: [%s0-9_]".formatted(Literal.PROPOSITIONS))); group.add(name, StringValidators.REQUIRE_NON_EMPTY_STRING); // Endpoints final LabeledNode sourceNode = g.getSource(e); final LabeledNode destNode = g.getDest(e); jp.add(new JLabel("Endpoints:")); jp.add(new JLabel(sourceNode + "→")); jp.add(new JLabel("→" + destNode)); // Default Value Integer v; // Integer v = e.getInitialValue(); // final JTextField value = new JTextField((v == null || v.equals(Constants.INT_POS_INFINITE)) ? "" : v.toString()); // jl = new JLabel("Initial Value:"); // jl.setLabelFor(value); // jp.add(jl); // jp.add(value); // setConditionToEnable(value, viewerName, false); // jp.add(new JLabel("Syntax: " + Constants.labeledValueRE)); // group.add(value, StringValidators.regexp(Constants.labeledValueRE, "Check the syntax!", false)); // Type // Group the radio buttons. final ButtonGroup buttonGroup = new ButtonGroup(); jp.add(new JLabel("Edge type: ")); final JRadioButton constraintButton = new JRadioButton(Edge.ConstraintType.requirement.toString()); constraintButton.setActionCommand(Edge.ConstraintType.requirement.toString()); constraintButton.setSelected(e.getConstraintType() == Edge.ConstraintType.requirement); setConditionToEnable(constraintButton, viewerName, false); jp.add(constraintButton); buttonGroup.add(constraintButton); boolean ctgAdded = false; final JRadioButton contingentButton = new JRadioButton(Edge.ConstraintType.contingent.toString()); if (g.getType() == NetworkType.CSTNU || g.getType() == NetworkType.CSTNPSU || g.getType() == NetworkType.STNU) { contingentButton.setActionCommand(Edge.ConstraintType.contingent.toString()); contingentButton.setSelected(e.isContingentEdge()); setConditionToEnable(contingentButton, viewerName, false); jp.add(contingentButton); buttonGroup.add(contingentButton); jp.add(new JLabel(""));// in order to jump a cell ctgAdded = true; } final JRadioButton derivedButton = new JRadioButton(Edge.ConstraintType.derived.toString()); derivedButton.setActionCommand(Edge.ConstraintType.derived.toString()); derivedButton.setSelected(e.getConstraintType() == Edge.ConstraintType.derived || e.getConstraintType() == Edge.ConstraintType.internal); derivedButton.setEnabled(false); jp.add(derivedButton); buttonGroup.add(derivedButton); if (ctgAdded) { jp.add(new JLabel(""));// in order to jump a cell } JTextField jt; int i = 0; JTextField jtLabel, jtValue; int inputsN = -1; JTextField[] labelInputs = null; JTextField[] newIntInputs = null; Integer[] oldIntInputs = null; if (e.isSTNEdge() || e.isSTNUEdge()) { inputsN = 1; newIntInputs = new JTextField[inputsN]; oldIntInputs = new Integer[inputsN]; // Show value label // jp.add(new JLabel(""));// in order to jump a cell jp.add(new JLabel("Value: "));// in order to jump a cell // Show value oldIntInputs[0] = Integer.valueOf(((STNEdge) e).getValue()); jtValue = new JTextField(Constants.formatInt(oldIntInputs[0])); newIntInputs[0] = jtValue; setConditionToEnable(jtValue, viewerName, false); jp.add(jtValue); group.add(jtValue, StringValidators.regexp(Constants.LabeledValueRE + "|", "Integer please or let it empty!", false)); // Show syntax jt = new JTextField("RE: " + Constants.LabeledValueRE); setConditionToEnable(jt, viewerName, true); jp.add(jt); // if (editorPanel) { // jtValue = new JTextField(); // newIntInputs[i] = jtValue; // oldIntInputs[i] = null; // setConditionToEnable(jtValue, viewerName, false); // jp.add(jtValue); // group.add(jtValue, StringValidators.regexp(Constants.LabeledValueRE + "|", "Integer please or let it empty!", false)); // } } if (e.isSTNUEdge()) { final STNUEdge e1 = (STNUEdge) e; final String labeledValue = e1.getLabeledValueFormatted(); if (!labeledValue.isEmpty()) { // jp.add(new JLabel(""));// in order to jump a cell jp.add(new JLabel("Case value: "));// in order to jump a cell jtValue = new JTextField(labeledValue); setConditionToEnable(jtValue, viewerName, true); jp.add(jtValue); } } if (e.isCSTNEdge()) { // Show possible labeled values final Set> labeledValueSet = ((CSTNEdge) e).getLabeledValues(); jp.add(new JLabel("Labeled value syntax:")); jt = new JTextField(Label.LABEL_RE); setConditionToEnable(jt, viewerName, false); jp.add(jt); jt = new JTextField(Constants.LabeledValueRE); setConditionToEnable(jt, viewerName, false); jp.add(jt); inputsN = labeledValueSet.size() + 1; labelInputs = new JTextField[inputsN]; newIntInputs = new JTextField[inputsN]; oldIntInputs = new Integer[inputsN]; if (!labeledValueSet.isEmpty()) { for (final Entry