/* GUIConfig.java * * This class provides a window for configuration options. * (c) 2006 EduMIPS64 project - Rizzo Vanni G, Trubia Massimo (FPU modifications) * * This file is part of the EduMIPS64 project, and is released under the GNU * General Public License. * * 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 org.edumips64.ui.swing; import org.edumips64.utils.ConfigKey; import org.edumips64.utils.ConfigStore; import org.edumips64.utils.ConfigStoreTypeException; import org.edumips64.utils.CurrentLocale; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JColorChooser; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.SwingConstants; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.util.HashMap; import java.util.LinkedList; import java.util.Map; import java.util.logging.Logger; /** * This class provides a window for configuration options. */ public class GUIConfig extends JDialog { private static final Logger logger = Logger.getLogger(GUIConfig.class.getName()); // Local cache of the configuration values that will need to be applied to // the configuration backend. private Map<ConfigKey, Object> cache; private ConfigStore config; public GUIConfig(final JFrame owner, ConfigStore config) { super(owner, CurrentLocale.getString("Config.ITEM"), true); this.config = config; logger.info("Building a new GUIConfig instance."); String MAIN = CurrentLocale.getString("Config.MAIN"); String APPEARANCE = CurrentLocale.getString("Config.APPEARANCE"); String BEHAVIOR = CurrentLocale.getString("Config.BEHAVIOR"); String FPUEXCEPTIONS = CurrentLocale.getString("Config.FPUEXCEPTIONS"); String FPUROUNDING = CurrentLocale.getString("Config.FPUROUNDING"); cache = new HashMap<>(); JTabbedPane tabPanel = new JTabbedPane(); tabPanel.addTab(MAIN, makeMainPanel()); tabPanel.addTab(BEHAVIOR, makeBehaviorPanel()); tabPanel.addTab(FPUEXCEPTIONS, makeExceptionsPanel()); tabPanel.addTab(FPUROUNDING, makeRoundingPanel()); tabPanel.addTab(APPEARANCE, makeAppearancePanel()); final JPanel buttonPanel = new JPanel(); buttonPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); addButtons(buttonPanel); Container content = getContentPane(); content.add(tabPanel, BorderLayout.CENTER); content.add(buttonPanel, BorderLayout.PAGE_END); //pack(); int width = 700; int height = 300; setSize(width, height); setLocation((getScreenWidth() - getWidth()) / 2, (getScreenHeight() - getHeight()) / 2); setVisible(true); } private GridBagLayout gbl; private GridBagConstraints gbc; private JPanel makeMainPanel() { gbl = new GridBagLayout(); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(0, 10, 0, 10); JPanel panel = new JPanel(); panel.setLayout(gbl); panel.setAlignmentY(JPanel.TOP_ALIGNMENT); int row = 2; addRow(panel, row++, ConfigKey.FORWARDING, new JCheckBox()); addRow(panel, row++, ConfigKey.N_STEPS, new JNumberField()); // fill remaining vertical space grid_add(panel, new JPanel(), gbl, gbc, 0, 1, 0, row, GridBagConstraints.REMAINDER, 1); return panel; } private JPanel makeBehaviorPanel() { gbl = new GridBagLayout(); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(0, 10, 0, 10); JPanel panel = new JPanel(); panel.setLayout(gbl); panel.setAlignmentY(JPanel.TOP_ALIGNMENT); int row = 2; addRow(panel, row++, ConfigKey.WARNINGS, new JCheckBox()); addRow(panel, row++, ConfigKey.VERBOSE, new JCheckBox()); addRow(panel, row++, ConfigKey.SLEEP_INTERVAL, new JNumberField()); addRow(panel, row++, ConfigKey.SYNC_EXCEPTIONS_MASKED, new JCheckBox()); addRow(panel, row++, ConfigKey.SYNC_EXCEPTIONS_TERMINATE, new JCheckBox()); // fill remaining vertical space grid_add(panel, new JPanel(), gbl, gbc, 0, 1, 0, row, GridBagConstraints.REMAINDER, 1); return panel; } private JPanel makeExceptionsPanel() { gbl = new GridBagLayout(); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(0, 10, 0, 10); JPanel panel = new JPanel(); panel.setLayout(gbl); panel.setAlignmentY(JPanel.TOP_ALIGNMENT); int row = 2; addRow(panel, row++, ConfigKey.FP_INVALID_OPERATION, new JCheckBox()); addRow(panel, row++, ConfigKey.FP_OVERFLOW, new JCheckBox()); addRow(panel, row++, ConfigKey.FP_UNDERFLOW, new JCheckBox()); addRow(panel, row++, ConfigKey.FP_DIVIDE_BY_ZERO, new JCheckBox()); // fill remaining vertical space grid_add(panel, new JPanel(), gbl, gbc, 0, 1, 0, row, GridBagConstraints.REMAINDER, 1); return panel; } private JPanel makeRoundingPanel() { ButtonGroup bg = new ButtonGroup(); JRadioButton rdoNearest = new JRadioButton(); JRadioButton rdoTowardZero = new JRadioButton(); JRadioButton rdoTowardsPlusInfinity = new JRadioButton(); JRadioButton rdoTowardsMinusInfinity = new JRadioButton(); bg.add(rdoNearest); bg.add(rdoTowardZero); bg.add(rdoTowardsPlusInfinity); bg.add(rdoTowardsMinusInfinity); gbl = new GridBagLayout(); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(0, 10, 0, 10); JPanel panel = new JPanel(); panel.setLayout(gbl); panel.setAlignmentY(JPanel.TOP_ALIGNMENT); int row = 2; addRow(panel, row++, ConfigKey.FP_NEAREST, rdoNearest); addRow(panel, row++, ConfigKey.FP_TOWARDS_ZERO, rdoTowardZero); addRow(panel, row++, ConfigKey.FP_TOWARDS_PLUS_INFINITY, rdoTowardsPlusInfinity); addRow(panel, row++, ConfigKey.FP_TOWARDS_MINUS_INFINITY, rdoTowardsMinusInfinity); // fill remaining vertical space grid_add(panel, new JPanel(), gbl, gbc, 0, 1, 0, row, GridBagConstraints.REMAINDER, 1); return panel; } private JPanel makeAppearancePanel() { gbl = new GridBagLayout(); gbc = new GridBagConstraints(); gbc.anchor = GridBagConstraints.WEST; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.insets = new Insets(0, 10, 0, 10); JPanel panel = new JPanel(); panel.setLayout(gbl); panel.setAlignmentY(JPanel.TOP_ALIGNMENT); int row = 2; addRow(panel, row++, ConfigKey.IF_COLOR, new JButton()); addRow(panel, row++, ConfigKey.ID_COLOR, new JButton()); addRow(panel, row++, ConfigKey.EX_COLOR, new JButton()); addRow(panel, row++, ConfigKey.MEM_COLOR, new JButton()); addRow(panel, row++, ConfigKey.WB_COLOR, new JButton()); addRow(panel, row++, ConfigKey.FP_ADDER_COLOR, new JButton()); addRow(panel, row++, ConfigKey.FP_MULTIPLIER_COLOR, new JButton()); addRow(panel, row++, ConfigKey.FP_DIVIDER_COLOR, new JButton()); addRow(panel, row++, ConfigKey.FP_LONG_DOUBLE_VIEW, new JCheckBox()); addRow(panel, row++, ConfigKey.SHOW_ALIASES, new JCheckBox()); // fill remaining vertical space grid_add(panel, new JPanel(), gbl, gbc, 0, 1, 0, row, GridBagConstraints.REMAINDER, 1); return panel; } // Monster function that adds a given row (label + control) to a given // JPanel, and sets its behaviour according to the type of control. private void addRow(JPanel panel, final int row, final ConfigKey key, final JComponent comp) { String title = CurrentLocale.getString("Config." + String.valueOf(key).toUpperCase()); String tip = CurrentLocale.getString("Config." + String.valueOf(key).toUpperCase() + ".tip"); //Setting title JLabel label = new JLabel(title); label.setHorizontalAlignment(JLabel.RIGHT); label.setToolTipText(tip); grid_add(panel, label, gbl, gbc, .1, 0, 0, row, 1, 1); if (comp instanceof JCheckBox) { final JCheckBox cbox = (JCheckBox) comp; //Setting Component cbox.setHorizontalAlignment(SwingConstants.LEFT); cbox.setVerticalAlignment(SwingConstants.CENTER); cbox.setSelected(config.getBoolean(key)); cbox.setAction(new AbstractAction() { public void actionPerformed(ActionEvent e) { logger.info("Changing " + key + " to " + cbox.getModel().isSelected()); cache.put(key, cbox.getModel().isSelected()); } }); } else if (comp instanceof JRadioButton) { final JRadioButton rbut = (JRadioButton) comp; rbut.setHorizontalAlignment(SwingConstants.LEFT); rbut.setVerticalAlignment(SwingConstants.CENTER); rbut.setSelected(config.getBoolean(key)); // When a radio button is clicked, the other buttons must be deselected. // TODO: more generic handling of radio buttons: currently we have only // one and this code is tailored for it. rbut.setAction(new AbstractAction() { public void actionPerformed(ActionEvent e) { LinkedList<ConfigKey> keys = new LinkedList<>(); keys.add(ConfigKey.FP_NEAREST); keys.add(ConfigKey.FP_TOWARDS_ZERO); keys.add(ConfigKey.FP_TOWARDS_PLUS_INFINITY); keys.add(ConfigKey.FP_TOWARDS_MINUS_INFINITY); cache.put(key, true); keys.remove(key); for (ConfigKey k : keys) { cache.put(k, false); } } }); } else if (comp instanceof JNumberField) { final JNumberField number = (JNumberField) comp; number.setNumber(config.getInt(key)); number.addFocusListener(new FocusAdapter() { public void focusLost(FocusEvent e) { if (number.isNumber()) { cache.put(key, number.getNumber()); } else { logger.info("Error, the specified value is not a number."); JOptionPane.showMessageDialog(GUIConfig.this, CurrentLocale.getString("INT_FORMAT_EXCEPTION"), CurrentLocale.getString("ERROR"), JOptionPane.ERROR_MESSAGE); } } }); number.setAction(new AbstractAction() { public void actionPerformed(ActionEvent e) { if (number.isNumber()) { cache.put(key, number.getNumber()); } else { logger.info("Error, the specified value is not a number."); JOptionPane.showMessageDialog(GUIConfig.this, CurrentLocale.getString("INT_FORMAT_EXCEPTION"), CurrentLocale.getString("ERROR"), JOptionPane.ERROR_MESSAGE); } } }); } else if (comp instanceof JTextField) { final JTextField text = (JTextField) comp; text.setText(config.getString(key)); text.addFocusListener(new FocusAdapter() { public void focusLost(FocusEvent e) { logger.info("focus"); cache.put(key, text.getText()); } }); text.setAction(new AbstractAction() { public void actionPerformed(ActionEvent e) { logger.info("abstract"); cache.put(key, text.getText()); } }); } else if (comp instanceof JButton) { final JButton button = (JButton) comp; button.setBounds(0, 0, 50, 10); button.setBackground(new Color(config.getInt(key))); button.addActionListener(e -> { Color color = JColorChooser.showDialog( GUIConfig.this, CurrentLocale.getString("Config." + String.valueOf(key).toUpperCase()), button.getBackground()); if (color != null) { button.setBackground(color); cache.put(key, button.getBackground().getRGB()); } }); } grid_add(panel, comp, gbl, gbc, .2, 0, 1, row, 1, 1); panel.setMinimumSize(new java.awt.Dimension(10, 10)); } private static void grid_add( JComponent jc_, //pannello contenitore Component c_, //Componente da inserire GridBagLayout gbl_, //Layout da usare GridBagConstraints gbc_, //Costanti double weightx_, double weighty_, int x_, int y_, int w_, int h_ ) { gbc_.weightx = weightx_; gbc_.weighty = weighty_; gbc_.gridx = x_; gbc_.gridy = y_; gbc_.gridwidth = w_; gbc_.gridheight = h_; gbl_.setConstraints(c_, gbc_); jc_.add(c_); } private void addButtons(JPanel buttonPanel) { final JButton okButton = new JButton("OK"); final JButton cancelButton = new JButton("Cancel"); buttonPanel.add(okButton); buttonPanel.add(cancelButton); //Setting Action for each buttons cancelButton.addActionListener(e -> setVisible(false)); okButton.addActionListener(e -> { try { // Flush the cache to the actual configuration. config.mergeFromGenericMap(cache); // Might be needed if show_alias is changed. org.edumips64.Main.getGUIFrontend().updateComponents(); org.edumips64.Main.updateCGT(); } catch (ConfigStoreTypeException ex) { logger.severe("Unknown type encountered while storing the configuration."); } setVisible(false); }); } private static int getScreenWidth() { return (int) Toolkit.getDefaultToolkit().getScreenSize().getWidth(); } private static int getScreenHeight() { return (int) Toolkit.getDefaultToolkit().getScreenSize().getHeight(); } }