<commit_before>package de.uni_hannover.sra.minimax_simulator.gui;

import de.uni_hannover.sra.minimax_simulator.Main;
import de.uni_hannover.sra.minimax_simulator.gui.util.HexSpinnerValueFactory;
import de.uni_hannover.sra.minimax_simulator.model.configuration.MachineConfiguration;
import de.uni_hannover.sra.minimax_simulator.model.configuration.event.MachineConfigEvent;
import de.uni_hannover.sra.minimax_simulator.model.configuration.event.MachineConfigListEvent;
import de.uni_hannover.sra.minimax_simulator.model.configuration.event.MachineConfigListener;
import de.uni_hannover.sra.minimax_simulator.model.configuration.mux.*;
import de.uni_hannover.sra.minimax_simulator.resources.TextResource;
import de.uni_hannover.sra.minimax_simulator.gui.common.NullAwareIntFormatter;
import de.uni_hannover.sra.minimax_simulator.ui.UIUtil;
import de.uni_hannover.sra.minimax_simulator.ui.common.dialogs.*;
import de.uni_hannover.sra.minimax_simulator.util.Util;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.StringConverter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * <b>FXController of the MuxView</b><br>
 * <br>
 * This controller handles every GUI interaction with the multiplexer {@link Tab}.
 *
 * @author <NAME>
 */
public class MuxView implements MachineConfigListener {

    private final TextResource _res;
    private MachineConfiguration _config;

    @FXML private TitledPane paneMuxA;
    @FXML private TitledPane paneMuxB;
    @FXML private TitledPane paneSelectedConnection;

    @FXML private TableView<MuxTableModel> tableMuxA;
    @FXML private TableColumn<MuxTableModel, String> col_mux_a_code;
    @FXML private TableColumn<MuxTableModel, String> col_mux_a_source;
    @FXML private TableColumn<MuxTableModel, String> col_mux_a_extended;
    @FXML private Button btnMoveUpMuxA;
    @FXML private Button btnMoveDownMuxA;
    @FXML private Button btnNewMuxA;
    @FXML private Button btnRemoveMuxA;

    @FXML private TableView<MuxTableModel> tableMuxB;
    @FXML private TableColumn<MuxTableModel, String> col_mux_b_code;
    @FXML private TableColumn<MuxTableModel, String> col_mux_b_source;
    @FXML private TableColumn<MuxTableModel, String> col_mux_b_extended;
    @FXML private Button btnMoveUpMuxB;
    @FXML private Button btnMoveDownMuxB;
    @FXML private Button btnNewMuxB;
    @FXML private Button btnRemoveMuxB;

    @FXML private RadioButton radioRegister;
    @FXML private ComboBox<MuxInput> cbRegister;
    @FXML private RadioButton radioConstant;
    @FXML private Label lblDec;
    @FXML private Label lblHex;
    @FXML private Spinner<Integer> spinnerDec;
    @FXML private Spinner<Integer> spinnerHex;
    @FXML private Button btnSave;

    private ToggleGroup tgroup = new ToggleGroup();

    /**
     * The constructor initializes the final variables.
     */
    public MuxView() {
        _res = Main.getTextResource("machine").using("mux");
    }

    /**
     * This method is called during application start up and initializes the MuxView
     * as much as possible without having any project data.
     */
    public void initialize() {
        setLocalizedTexts();

        radioRegister.setToggleGroup(tgroup);
        radioConstant.setToggleGroup(tgroup);
    }

    /**
     * Sets localized texts from resource for the GUI elements.
     */
    private void setLocalizedTexts() {
        paneMuxA.setText(_res.format("table.title", "A"));
        paneMuxB.setText(_res.format("table.title", "B"));
        final List<Labeled> controls = new ArrayList<>(Arrays.asList(paneSelectedConnection, radioRegister, radioConstant, lblDec, lblHex, btnSave));
        for (Labeled con : controls) {
            con.setText(_res.get(con.getId().replace("_", ".")));
        }
    }

    /**
     * This method is called from the main controller if a new project was created or opened.
     * It initializes the two multiplexer {@link TableView}s as well as the register {@link ComboBox} because they need project data.
     */
    public void initMuxView() {
        _config = Main.getWorkspace().getProject().getMachineConfiguration();
        _config.addMachineConfigListener(this);
        initTableMuxA();
        initTableMuxB();

        // set a new string converter for the combo box, otherwise the toString method of MuxInput would be used
        cbRegister.setConverter(new StringConverter<MuxInput>() {
            @Override
            public String toString(MuxInput muxInput) {
                if (muxInput == null) {
                    return null;
                } else {
                    return muxInput.getName();
                }
            }

            @Override
            public MuxInput fromString(String muxInputString) {
                return null;
            }
        });

        cbRegister.valueProperty().addListener((obs, oldValue, newValue) ->
                updateSaveButton());

        updateRegisterComboBox();

        tgroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
            @Override
            public void changed(ObservableValue<? extends Toggle> ov, Toggle t, Toggle t1) {

                RadioButton chk = (RadioButton) t1.getToggleGroup().getSelectedToggle();
                boolean disable;
                if (chk.equals(radioRegister)) {
                    disable = true;
                } else if (chk.equals(radioConstant)) {
                    disable = false;
                } else {
                    return;
                }
                cbRegister.setDisable(!disable);
                lblDec.setDisable(disable);
                lblHex.setDisable(disable);
                spinnerHex.setDisable(disable);
                spinnerDec.setDisable(disable);

                updateSaveButton();
            }
        });

        initSpinners();
    }

    /**
     * Updates the {@link ComboBox} containing the registers.
     */
    private void updateRegisterComboBox() {
        cbRegister.setItems(FXCollections.observableArrayList(_config.getAvailableSources()));
    }

    /**
     * Sets up two synchronous {@link Spinner}s with different value representation.
     */
    private void initSpinners() {
        SpinnerValueFactory.IntegerSpinnerValueFactory vFacDec = new SpinnerValueFactory.IntegerSpinnerValueFactory(Integer.MIN_VALUE, Integer.MAX_VALUE);
        vFacDec.setWrapAround(true);
        spinnerDec.setValueFactory(vFacDec);
        spinnerDec.getEditor().setTextFormatter(new NullAwareIntFormatter(NullAwareIntFormatter.Mode.DEC));
        spinnerDec.valueProperty().addListener((obs, oldValue, newValue) -> {
            updateSaveButton();
            spinnerHex.getValueFactory().setValue(newValue);
        });

        HexSpinnerValueFactory vFacHex = new HexSpinnerValueFactory();
        vFacHex.setWrapAround(true);
        spinnerHex.setValueFactory(vFacHex);
        spinnerHex.getEditor().setTextFormatter(new NullAwareIntFormatter(NullAwareIntFormatter.Mode.HEX));
        spinnerHex.valueProperty().addListener((observable, oldValue, newValue) -> {
            spinnerDec.getValueFactory().setValue(newValue);
        });

        vFacDec.setValue(0);
        vFacHex.setValue(0);
    }

    /**
     * Initializes the {@link TableView} for multiplexer A.
     */
    private void initTableMuxA() {
        col_mux_a_code.setCellValueFactory(new PropertyValueFactory<>("code"));
        col_mux_a_source.setCellValueFactory(new PropertyValueFactory<>("source"));
        col_mux_a_extended.setCellValueFactory(new PropertyValueFactory<>("extended"));

        tableMuxA.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {<commit_msg>Bugfix: spinners at MuxView were not synchronous during input of new values<commit_after>package de.uni_hannover.sra.minimax_simulator.gui;

import de.uni_hannover.sra.minimax_simulator.Main;
import de.uni_hannover.sra.minimax_simulator.gui.util.HexSpinnerValueFactory;
import de.uni_hannover.sra.minimax_simulator.model.configuration.MachineConfiguration;
import de.uni_hannover.sra.minimax_simulator.model.configuration.event.MachineConfigEvent;
import de.uni_hannover.sra.minimax_simulator.model.configuration.event.MachineConfigListEvent;
import de.uni_hannover.sra.minimax_simulator.model.configuration.event.MachineConfigListener;
import de.uni_hannover.sra.minimax_simulator.model.configuration.mux.*;
import de.uni_hannover.sra.minimax_simulator.resources.TextResource;
import de.uni_hannover.sra.minimax_simulator.gui.common.NullAwareIntFormatter;
import de.uni_hannover.sra.minimax_simulator.ui.UIUtil;
import de.uni_hannover.sra.minimax_simulator.ui.common.dialogs.*;
import de.uni_hannover.sra.minimax_simulator.util.Util;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.util.StringConverter;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

/**
 * <b>FXController of the MuxView</b><br>
 * <br>
 * This controller handles every GUI interaction with the multiplexer {@link Tab}.
 *
 * @author <NAME>
 */
public class MuxView implements MachineConfigListener {

    private final TextResource _res;
    private MachineConfiguration _config;

    @FXML private TitledPane paneMuxA;
    @FXML private TitledPane paneMuxB;
    @FXML private TitledPane paneSelectedConnection;

    @FXML private TableView<MuxTableModel> tableMuxA;
    @FXML private TableColumn<MuxTableModel, String> col_mux_a_code;
    @FXML private TableColumn<MuxTableModel, String> col_mux_a_source;
    @FXML private TableColumn<MuxTableModel, String> col_mux_a_extended;
    @FXML private Button btnMoveUpMuxA;
    @FXML private Button btnMoveDownMuxA;
    @FXML private Button btnNewMuxA;
    @FXML private Button btnRemoveMuxA;

    @FXML private TableView<MuxTableModel> tableMuxB;
    @FXML private TableColumn<MuxTableModel, String> col_mux_b_code;
    @FXML private TableColumn<MuxTableModel, String> col_mux_b_source;
    @FXML private TableColumn<MuxTableModel, String> col_mux_b_extended;
    @FXML private Button btnMoveUpMuxB;
    @FXML private Button btnMoveDownMuxB;
    @FXML private Button btnNewMuxB;
    @FXML private Button btnRemoveMuxB;

    @FXML private RadioButton radioRegister;
    @FXML private ComboBox<MuxInput> cbRegister;
    @FXML private RadioButton radioConstant;
    @FXML private Label lblDec;
    @FXML private Label lblHex;
    @FXML private Spinner<Integer> spinnerDec;
    @FXML private Spinner<Integer> spinnerHex;
    @FXML private Button btnSave;

    private ToggleGroup tgroup = new ToggleGroup();

    /**
     * The constructor initializes the final variables.
     */
    public MuxView() {
        _res = Main.getTextResource("machine").using("mux");
    }

    /**
     * This method is called during application start up and initializes the MuxView
     * as much as possible without having any project data.
     */
    public void initialize() {
        setLocalizedTexts();

        radioRegister.setToggleGroup(tgroup);
        radioConstant.setToggleGroup(tgroup);
    }

    /**
     * Sets localized texts from resource for the GUI elements.
     */
    private void setLocalizedTexts() {
        paneMuxA.setText(_res.format("table.title", "A"));
        paneMuxB.setText(_res.format("table.title", "B"));
        final List<Labeled> controls = new ArrayList<>(Arrays.asList(paneSelectedConnection, radioRegister, radioConstant, lblDec, lblHex, btnSave));
        for (Labeled con : controls) {
            con.setText(_res.get(con.getId().replace("_", ".")));
        }
    }

    /**
     * This method is called from the main controller if a new project was created or opened.
     * It initializes the two multiplexer {@link TableView}s as well as the register {@link ComboBox} because they need project data.
     */
    public void initMuxView() {
        _config = Main.getWorkspace().getProject().getMachineConfiguration();
        _config.addMachineConfigListener(this);
        initTableMuxA();
        initTableMuxB();

        // set a new string converter for the combo box, otherwise the toString method of MuxInput would be used
        cbRegister.setConverter(new StringConverter<MuxInput>() {
            @Override
            public String toString(MuxInput muxInput) {
                if (muxInput == null) {
                    return null;
                } else {
                    return muxInput.getName();
                }
            }

            @Override
            public MuxInput fromString(String muxInputString) {
                return null;
            }
        });

        cbRegister.valueProperty().addListener((obs, oldValue, newValue) ->
                updateSaveButton());

        updateRegisterComboBox();

        tgroup.selectedToggleProperty().addListener(new ChangeListener<Toggle>() {
            @Override
            public void changed(ObservableValue<? extends Toggle> ov, Toggle t, Toggle t1) {

                RadioButton chk = (RadioButton) t1.getToggleGroup().getSelectedToggle();
                boolean disable;
                if (chk.equals(radioRegister)) {
                    disable = true;
                } else if (chk.equals(radioConstant)) {
                    disable = false;
                } else {
                    return;
                }
                cbRegister.setDisable(!disable);
                lblDec.setDisable(disable);
                lblHex.setDisable(disable);
                spinnerHex.setDisable(disable);
                spinnerDec.setDisable(disable);

                updateSaveButton();
            }
        });

        initSpinners();
    }

    /**
     * Updates the {@link ComboBox} containing the registers.
     */
    private void updateRegisterComboBox() {
        cbRegister.setItems(FXCollections.observableArrayList(_config.getAvailableSources()));
    }

    /**
     * Sets up two synchronous {@link Spinner}s with different value representation.
     */
    private void initSpinners() {
        SpinnerValueFactory.IntegerSpinnerValueFactory vFacDec = new SpinnerValueFactory.IntegerSpinnerValueFactory(Integer.MIN_VALUE, Integer.MAX_VALUE);
        vFacDec.setWrapAround(true);
        spinnerDec.setValueFactory(vFacDec);
        spinnerDec.getEditor().setTextFormatter(new NullAwareIntFormatter(NullAwareIntFormatter.Mode.DEC));
        spinnerDec.getEditor().textProperty().addListener((obs, oldValue, newValue) -> {
            updateSaveButton();
            spinnerHex.getValueFactory().setValue(Integer.valueOf(newValue));
        });

        HexSpinnerValueFactory vFacHex = new HexSpinnerValueFactory();
        vFacHex.setWrapAround(true);
        spinnerHex.setValueFactory(vFacHex);
        spinnerHex.getEditor().setTextFormatter(new NullAwareIntFormatter(NullAwareIntFormatter.Mode.HEX));
        spinnerHex.getEditor().textProperty().addListener((obs, oldValue, newValue) -> {
            updateSaveButton();
            spinnerDec.getValueFactory().setValue(Integer.valueOf(newValue, 16));
        });

        vFacDec.setValue(0);
        vFacHex.setValue(0);
    }

    /**
     * Initializes the {@link TableView} for multiplexer A.
     */
    private void initTableMuxA() {
        col_mux_a_code.setCellValueFactory(new PropertyValueFactory<>("code"));
        col_mux_a_source.setCellValueFactory(new PropertyValueFactory<>("source"));
        col_mux_a_extended.setCellValueFactory(new PropertyValueFactory<>("extended"));

        tableMuxA.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
{'fraction_non_alphanumeric': 0.09442772009584076, 'fraction_numerical': 0.0006143638262579099, 'mean_word_length': 3.188883170355121, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 59, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3021030', 'n_tokens_mistral': 4720, 'n_tokens_neox': 4603, 'n_words': 947}