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

edu.cmu.tetradapp.editor.ExpressionEditor Maven / Gradle / Ivy

The newest version!
///////////////////////////////////////////////////////////////////////////////
// For information as to what this class does, see the Javadoc, below.       //
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,       //
// 2007, 2008, 2009, 2010, 2014, 2015, 2022 by Peter Spirtes, Richard        //
// Scheines, Joseph Ramsey, and Clark Glymour.                               //
//                                                                           //
// 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 2 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, write to the Free Software               //
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA //
///////////////////////////////////////////////////////////////////////////////

package edu.cmu.tetradapp.editor;

import edu.cmu.tetrad.calculator.expression.Equation;
import edu.cmu.tetrad.calculator.expression.ExpressionSignature;
import edu.cmu.tetrad.calculator.parser.ExpressionParser;
import edu.cmu.tetrad.data.DataSet;
import edu.cmu.tetrad.util.NamingProtocol;

import javax.swing.*;
import java.awt.*;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.ParseException;
import java.util.LinkedList;
import java.util.List;

/**
 * An editor for expressions.
 *
 * @author Tyler Gibson
 */
class ExpressionEditor extends JPanel {


    /**
     * Normal selections color.
     */
    private static final Color SELECTION = new Color(204, 204, 255);
    /**
     * The variable field.
     */
    private final JTextField variable;
    /**
     * The expression field.
     */
    private final JTextField expression;
    /**
     * Parser.
     */
    private final ExpressionParser parser;
    /**
     * Focus listeners.
     */
    private final List listeners = new LinkedList<>();
    /**
     * The active selections if there is one.
     */
    private final List selections = new LinkedList<>();
    private final PositionsFocusListener positionsListener;
    /**
     * The last field to have focus.
     */
    private JTextField lastFocused;
    /**
     * States whether the remove box is clicked.
     */
    private boolean remove;


    /**
     * Creates the editor given the data set being worked on.
     *
     * @param data a {@link edu.cmu.tetrad.data.DataSet} object
     * @param lhs  a {@link java.lang.String} object
     * @param rhs  a {@link java.lang.String} object
     */
    public ExpressionEditor(DataSet data, String lhs, String rhs) {
        this.parser = new ExpressionParser(data.getVariableNames(), ExpressionParser.RestrictionType.MAY_ONLY_CONTAIN);

        this.variable = new JTextField(5);
        this.variable.setText(lhs);
        this.expression = new JTextField(25);
        this.expression.setText(rhs);

        this.variable.addFocusListener(new VariableFocusListener(this.variable));
        this.expression.addFocusListener(new ExpressionFocusListener(this.expression));

        this.positionsListener = new PositionsFocusListener();
        this.expression.addFocusListener(this.positionsListener);

        Box box = Box.createHorizontalBox();
        box.add(this.variable);
        box.add(Box.createHorizontalStrut(5));
        box.add(new JLabel("="));
        box.add(Box.createHorizontalStrut(5));
        box.add(this.expression);
        JCheckBox checkBox = new JCheckBox();
        checkBox.addActionListener(e -> {
            JCheckBox b = (JCheckBox) e.getSource();
            ExpressionEditor.this.remove = b.isSelected();
        });
        box.add(Box.createHorizontalStrut(2));
        box.add(checkBox);
        box.add(Box.createHorizontalGlue());

        add(box);


    }

    //============================ Public Method ======================================//

    /**
     * 

getEquation.

* * @return the expression. * @throws java.text.ParseException - If the values in the editor are not well-formed. */ public Equation getEquation() throws ParseException { if (!NamingProtocol.isLegalName(this.variable.getText())) { this.variable.setSelectionColor(Color.RED); this.variable.select(0, this.variable.getText().length()); this.variable.grabFocus(); throw new ParseException(NamingProtocol.getProtocolDescription(), 1); } String equation = this.variable.getText() + "=" + this.expression.getText(); try { return this.parser.parseEquation(equation); } catch (ParseException ex) { this.expression.setSelectionColor(Color.RED); this.expression.select(ex.getErrorOffset() - 1, this.expression.getText().length()); this.expression.grabFocus(); throw ex; } } /** * Adds a focus listener that will be notified about the focus events of the fields in the editor. The listener * will only be notified of gain focus events. * * @param listener a {@link java.awt.event.FocusListener} object */ public void addFieldFocusListener(FocusListener listener) { this.listeners.add(listener); } /** * Sets the given variable in the variable field. * * @param var - The variable to set. * @param append - States whether it should append to the field's getModel value or not. */ private void setVariable(String var, boolean append) { if (append) { this.variable.setText(this.variable.getText() + var); } else { this.variable.setText(var); } } /** * Sets the given expression fragment in the expression field. * * @param exp - Expression value to set. * @param append States whether it should append to the field's getModel value or not. */ private void setExpression(String exp, boolean append) { if (exp == null) { return; } if (!this.selections.isEmpty()) { this.expression.grabFocus(); int start = this.positionsListener.start; int end = this.positionsListener.end; if (start < end) { // expression.select(start, end); this.selections.add(new Selection(start, end)); this.expression.setCaretPosition(this.positionsListener.caretPosition); } String text = this.expression.getText(); Selection selection = this.selections.remove(0); if (caretInSelection(selection)) { this.expression.setText(text.substring(0, selection.x) + exp + text.substring(selection.y)); this.adjustSelections(selection, exp); this.highlightNextSelection(); this.positionsListener.start = this.expression.getSelectionStart(); this.positionsListener.end = this.expression.getSelectionEnd(); this.positionsListener.caretPosition = this.expression.getCaretPosition(); return; } } if (append) { this.expression.setText(this.expression.getText() + exp); } else { this.expression.setText(exp); } this.positionsListener.start = 0; this.positionsListener.end = 0; this.positionsListener.caretPosition = 0; } /** * Adds the signature to the expression field. * * @param signature a {@link edu.cmu.tetrad.calculator.expression.ExpressionSignature} object */ public void addExpressionSignature(ExpressionSignature signature) { this.expression.grabFocus(); int start = this.positionsListener.start; int end = this.positionsListener.end; int caret = this.positionsListener.caretPosition; if (start < end) { // expression.select(start, end); this.selections.add(new Selection(start, end)); // expression.setCaretPosition(positionsListener.caretPosition); } String sig = signature.getSignature(); String text = this.expression.getText(); Selection selection = this.selections.isEmpty() ? null : this.selections.remove(0); // if empty add the sig with any selections. if (selection == null || !caretInSelection(selection)) { String newText = text.substring(0, caret) + signature.getSignature() + text.substring(caret); // String newText = text + signature.getSignature(); this.expression.setText(newText); addSelections(signature, newText, false); this.highlightNextSelection(); return; } // otherwise there is a selections so we want to insert this sig in it. String replacedText = text.substring(0, selection.x) + sig + text.substring(selection.y); this.expression.setText(replacedText); this.adjustSelections(selection, sig); addSelections(signature, replacedText, true); this.highlightNextSelection(); this.positionsListener.start = 0; this.positionsListener.end = 0; this.positionsListener.caretPosition = 0; } /** * Inserts the given symbol into the last focused field, of if there isn't one the expression field. * * @param append States whether it should append to the field's getModel value or not. * @param symbol a {@link java.lang.String} object */ public void insertLastFocused(String symbol, boolean append) { if (this.variable == this.lastFocused) { setVariable(symbol, append); } else { setExpression(symbol, append); } } /** *

removeSelected.

* * @return a boolean */ public boolean removeSelected() { return this.remove; } //========================== Private Methods ====================================// /** * States whether the caret is in the getModel selection, if not false is returned and all the selections are * removed (as the user moved the caret around). */ private boolean caretInSelection(Selection sel) { int caret = this.expression.getCaretPosition(); if (caret < sel.x || sel.y < caret) { this.selections.clear(); return false; } return true; } /** * Adds the selections for the given signature in the given text. */ private void addSelections(ExpressionSignature signature, String newText, boolean addFirst) { int offset = 0; for (int i = 0; i < signature.getNumberOfArguments(); i++) { String arg = signature.getArgument(i); int index = newText.indexOf(arg); int end = index + arg.length(); if (0 <= index) { if (addFirst) { this.selections.add(i, new Selection(offset + index, offset + end)); } else { this.selections.add(new Selection(offset + index, offset + end)); } } offset = offset + end; newText = newText.substring(end); } } private void fireGainedFocus() { FocusEvent evt = new FocusEvent(this, FocusEvent.FOCUS_GAINED); for (FocusListener l : this.listeners) { l.focusGained(evt); } } /** * Adjusts any getModel selections to the fact that the given selections was just replaced by the given string. */ private void adjustSelections(Selection selection, String inserted) { int dif = (selection.y - selection.x) - inserted.length(); for (Selection sel : this.selections) { sel.x = sel.x - dif; sel.y = sel.y - dif; } } /** * Highlights the next selection. */ private void highlightNextSelection() { System.out.println("Highlighting next selection."); if (!this.selections.isEmpty()) { Selection sel = this.selections.get(0); this.expression.setSelectionColor(ExpressionEditor.SELECTION); this.expression.select(sel.x, sel.y); this.expression.grabFocus(); } } //========================== Inner class ==============================// /** * Represents a 1D line. */ private static class Selection { private int x; private int y; public Selection(int x, int y) { this.x = x; this.y = y; } } private static class PositionsFocusListener extends FocusAdapter { private int start; private int end; private int caretPosition; public void focusLost(FocusEvent e) { JTextField textField = (JTextField) e.getSource(); this.start = textField.getSelectionStart(); this.end = textField.getSelectionEnd(); this.caretPosition = textField.getCaretPosition(); } } /** * Focus listener for the variable field. */ private class VariableFocusListener implements FocusListener { private final JTextField field; public VariableFocusListener(JTextField field) { this.field = field; } public void focusGained(FocusEvent e) { ExpressionEditor.this.lastFocused = this.field; fireGainedFocus(); } public void focusLost(FocusEvent e) { } } /** * Focus listener for the expression field. */ private class ExpressionFocusListener implements FocusListener { private final JTextField field; public ExpressionFocusListener(JTextField field) { this.field = field; } public void focusGained(FocusEvent e) { ExpressionEditor.this.lastFocused = this.field; fireGainedFocus(); } @Override public void focusLost(FocusEvent e) { } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy