/* * ALMA - Atacama Large Millimiter Array * (c) European Southern Observatory, 2008 * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package alma.acs.logging.preferences; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.ComponentOrientation; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.InputVerifier; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JTextField; import javax.swing.JPanel; import javax.swing.JRootPane; /** * A dialog to setup (expert) preferences. * * @author acaproni * */ public class ExpertPrefsDlg extends JDialog implements ActionListener { /** * A class containing the options for the number of logs. * <P> * Each option is a couple <code><label, value></code> where * <UL> * <LI> value is the value of the option * <LI> label is a label to show to the user for that option * </UL> */ public enum NumberOption { UNLIMITED("Unlimited",0), K100("100K",100000), K200("200K",200000), K300("300K",300000), K400("400K",400000), K500("500K",500000); public final String label; public final int value; /** * Constructor * * @param lbl The label to show in the combo box * @param val The number of minutes */ private NumberOption(String lbl, int val) { label=lbl; value=val; } public String toString() { return label; } /** * Return the <code>TimeOption</code> having the parameter * as value; * * @param val The value to get the <code>TimeOption</code> from * @return the <code>TimeOption</code> having the parameter as value or * <code>null</code> if there is no <code>TimeOption</code> * having the parameter as value */ public static NumberOption fromInt(int val) { for (NumberOption nOpt: NumberOption.values()) { if (nOpt.value==val) { return nOpt; } } return null; } } /** * A class containing the options for the time frame of logs * <P> * Each option is a couple <code><label, value></code> where * <UL> * <LI> value is the value of the option * <LI> label is a label to show to the user for that option * </UL> */ public enum TimeOption { UNLIMITED("Unlimited",0), H1("1h",60), H3("3h",180), H5("5h",300), H12("12h",720), D1("1d",1440); public final String label; public final int value; /** * Constructor * * @param lbl The label to show * @param val The number of logs */ private TimeOption(String lbl, int val) { label=lbl; value=val; } public String toString() { return label; } /** * Return the <code>TimeOption</code> having the parameter * as value; * * @param val The value to get the <code>TimeOption</code> from * @return the <code>TimeOption</code> having the parameter as value or * <code>null</code> if there is no <code>TimeOption</code> * having the parameter as value */ public static TimeOption fromInt(int val) { for (TimeOption tOpt: TimeOption.values()) { if (tOpt.value==val) { return tOpt; } } return null; } } /** * The verifier of the value written in a text field * * @author acaproni * */ private static class PassVerifier extends InputVerifier { /** * Low limit (inclusive) */ private final int limit; public PassVerifier(int lowLimit) { limit=lowLimit; } public boolean verify(JComponent input) { JTextField tf = (JTextField) input; Integer val; try { val=Integer.parseInt(tf.getText()); boolean ret= val>=limit; if (ret) { input.setForeground(Color.black); } else { input.setForeground(Color.red); } return ret; } catch (Exception e) { input.setForeground(Color.red); return false; } } } /** * <code>OptionWidgets</code> is essentially used to access the check boxes with a * meaningful name. * * @author acaproni * */ public enum OptionWidgets { MAX_NUM_OF_LOGS("Max num. of logs:",null), TIME_FRAME("Time frame:",null), MAX_INPUT_RATE( "Max rate of logs from NC: ", "<HTML><FONT color=red>!</FONT> Use with care: can cause loss of logs"), MAX_OUTPUT_RATE( "Max rate of logs in table: ", "<HTML><FONT color=red>!</FONT> Use with care: can cause out of memory"), DYNAMIC_DISCARD_LEVEL( "Dynamic discard level: ", "<HTML><FONT color=red>!</FONT> Use with care: can cause out of memory"); /** * The check box for this option * <P> * The check box is used to enable, disable an option */ public final JCheckBox enableCB=new JCheckBox(); /** * Constructor * * @param label The text of the check box * @param tooltip The tooltip */ private OptionWidgets(String label, String tooltip) { enableCB.setText(label); enableCB.setToolTipText(tooltip); } /** * * @return <code>true</code> if this option is enabled */ public boolean isOptionEnabled() { return enableCB.isSelected(); } /** * Return the <code>OptionWidgets</code> whose <code>JCheckBox</code> * is equal to the passed parameter. * Otherwise throws an <code>IllegalArgumentException</code> * * @param cb The <code>JCheckBox</code> to get the option from * @return the <code>OptionWidgets</code> whose <code>JCheckBox</code> * is equal to the passed parameter. * Otherwise throws an <code>IllegalArgumentException</code> */ public static OptionWidgets fromCheckBox(JCheckBox cb) { if (cb==null) { throw new IllegalArgumentException("cb can't be null"); } for (OptionWidgets opt: OptionWidgets.values()) { if (opt.enableCB==cb) { return opt; } } throw new IllegalArgumentException("The passed is not part of TimeOptions.enableCB"); } } /** * The preferences shown and changed by this panel * <P> * This is a copy of the object received in the constructor. * <BR> * In this implementation this property is filled with the values * from the GUI by <code>getPreferences()</code> * * @see getPreferences() */ private UserPreferences preferences; /** * The preferences received in the constructor and used to reset. */ private UserPreferences originalPreferences; // The ok and cancel buttons private JButton okBtn; private JButton cancelBtn; private JButton restoreBtn; /** * Say if the user pressed the OK or the Cancel button */ private boolean okBtnPressed=false; /** * The component to show this dialog over */ private Component owner; /** * The max number of logs in table */ private JComboBox maxLogsInTableCB = new JComboBox(NumberOption.values()); /** * The max time frame to keep in the table */ private JComboBox timeFrameCB = new JComboBox(TimeOption.values()); /** * The rate of logs from the NC */ private JTextField inputRateTF = new JTextField("0",8); /** * The rate of logs into the table */ private JTextField outputRateTF = new JTextField("0",8); /** * The threshold for the dynamic discarding of logs */ private JTextField dynThresholdTF = new JTextField("0",6); /** * The damping factor for the dynamic discarding of logs */ private JTextField dynDampingTF = new JTextField("0",6); /** * The time interval for the dynamic discarding of logs */ private JTextField dynIntervalTF = new JTextField("0",6); /** * Constructor * * @param owner The owner of the dialog * @param initialNumOfLogs The initial value for the num of logs * @param initialTimeFrame The initial value for the time frame (minutes) */ public ExpertPrefsDlg(Component owner, UserPreferences prefs) { super(); if (owner==null) { throw new IllegalArgumentException("The owner can't be null"); } if (prefs==null) { throw new IllegalArgumentException("The preferences can't be null"); } setTitle("Preferences"); setName("ExpertPrefsDlg"); this.owner=owner; this.originalPreferences=prefs; try { this.preferences=prefs.clone(); System.out.println("Prefs: "+preferences.getMaxNumOfLogs()+", "+preferences.getMinuteTimeFrame()+", "+preferences.getMaxInputRate()+", "+preferences.getMaxOutputRate()); } catch (CloneNotSupportedException e) { // This should not happen because UserPreferences implements Cloneable this.preferences=new UserPreferences(0,0,Integer.MAX_VALUE, Integer.MAX_VALUE); } setModal(true); this.setDefaultCloseOperation(DISPOSE_ON_CLOSE); buildWidgets(); initGUI(); ratioWidgets(); setVisible(true); } /** * @see java.awt.event.ActionListener * @see java.awt.event.ActionEvent */ public void actionPerformed(ActionEvent e) { if (e.getSource() instanceof JCheckBox) { enableOption((JCheckBox)e.getSource()); } else if (e.getSource()==okBtn) { okBtnPressed=true; setVisible(false); dispose(); } else if (e.getSource()==cancelBtn) { setVisible(false); dispose(); } else if (e.getSource()==restoreBtn) { try { preferences=originalPreferences.clone(); } catch (CloneNotSupportedException ce) { preferences=new UserPreferences(0,0,Integer.MAX_VALUE, Integer.MAX_VALUE); } ratioWidgets(); }else { System.err.println("Event not handled "+e.getSource()); } } /** * Builds the GUI * */ private void initGUI() { JRootPane mainPnl = this.getRootPane(); mainPnl.setLayout(new BorderLayout()); ///////////////////////////////////////////////////////////// // Add the table constraints (max num of logs and time frame) /////////////////////////////////////////////////////////// JPanel tablePnl = new JPanel(); tablePnl.setBorder(BorderFactory.createTitledBorder("Table constraints")); tablePnl.setLayout(new GridBagLayout()); GridBagConstraints constr = new GridBagConstraints(); // Num of logs constr.gridx=0; constr.gridy=0; constr.fill=GridBagConstraints.HORIZONTAL; constr.anchor=GridBagConstraints.WEST; constr.insets = new Insets(5,5,5,5); tablePnl.add(OptionWidgets.MAX_NUM_OF_LOGS.enableCB,constr); constr.gridx=1; constr.gridy=0; constr.anchor=GridBagConstraints.LINE_START; constr.insets = new Insets(5,5,5,5); constr.fill=GridBagConstraints.HORIZONTAL; tablePnl.add(maxLogsInTableCB,constr); // Time frame constr.gridx=0; constr.gridy=1; constr.anchor=GridBagConstraints.WEST; constr.insets = new Insets(5,5,5,5); tablePnl.add(OptionWidgets.TIME_FRAME.enableCB,constr); constr.gridx=1; constr.gridy=1; constr.anchor=GridBagConstraints.LINE_START; constr.insets = new Insets(5,5,5,5); tablePnl.add(timeFrameCB,constr); timeFrameCB.setEnabled(false); /// DISABLED OptionWidgets.TIME_FRAME.enableCB.setEnabled(false); // DISABLED /////////////////////////////////////////////////////////// // Add engine constraints /////////////////////////////////////////////////////////// JPanel enginePnl = new JPanel(); enginePnl.setBorder(BorderFactory.createTitledBorder("Engine constraints")); enginePnl.setLayout(new GridBagLayout()); // INPUT RATE constr.gridx=0; constr.gridy=0; constr.anchor=GridBagConstraints.LAST_LINE_START; constr.insets = new Insets(5,5,5,5); enginePnl.add(OptionWidgets.MAX_INPUT_RATE.enableCB,constr); constr.gridx=1; constr.gridy=0; constr.anchor=GridBagConstraints.LAST_LINE_START; constr.insets = new Insets(5,5,5,5); enginePnl.add(inputRateTF,constr); // Output RATE constr.gridx=0; constr.gridy=1; constr.anchor=GridBagConstraints.LAST_LINE_START; constr.insets = new Insets(5,5,5,5); enginePnl.add(OptionWidgets.MAX_OUTPUT_RATE.enableCB,constr); constr.gridx=1; constr.gridy=1; constr.anchor=GridBagConstraints.LAST_LINE_START; constr.insets = new Insets(5,5,5,5); enginePnl.add(outputRateTF,constr); // DYNAMIC DISCARD LEVEL JPanel pnl = new JPanel(); pnl.setLayout(new GridLayout(3,2)); pnl.add(new JLabel("Threshold: "),"1"); pnl.add(dynThresholdTF,"2"); pnl.add(new JLabel("Damping: "),"3"); pnl.add(dynDampingTF,"4"); pnl.add(new JLabel("Time: "),"5"); pnl.add(dynIntervalTF,"6"); constr.gridx=0; constr.gridy=2; constr.fill=GridBagConstraints.VERTICAL; constr.anchor=GridBagConstraints.LAST_LINE_START; constr.insets = new Insets(5,5,5,5); enginePnl.add(OptionWidgets.DYNAMIC_DISCARD_LEVEL.enableCB,constr); constr.gridx=1; constr.gridy=2; constr.anchor=GridBagConstraints.LAST_LINE_START; constr.insets = new Insets(5,5,5,5); enginePnl.add(pnl,constr); // Add the table and engine panels to the main panel mainPnl.add(tablePnl,BorderLayout.CENTER); mainPnl.add(enginePnl,BorderLayout.NORTH); // Add the OK, CANCEL buttons JPanel buttonsPnl = new JPanel(new BorderLayout()); JPanel okCancelPnl = new JPanel(); okCancelPnl.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); BoxLayout boxLayout = new BoxLayout(okCancelPnl,BoxLayout.LINE_AXIS); okCancelPnl.setLayout(boxLayout); okCancelPnl.setBorder(BorderFactory.createEmptyBorder(0, 10, 10, 10)); okBtn = new JButton("Ok"); okBtn.addActionListener(this); cancelBtn = new JButton("Cancel"); cancelBtn.addActionListener(this); okCancelPnl.add(okBtn,BorderLayout.WEST); okCancelPnl.add(Box.createRigidArea(new Dimension(10, 0))); okCancelPnl.add(cancelBtn,BorderLayout.EAST); JPanel restoreBtnPnl=new JPanel(new FlowLayout()); restoreBtn = new JButton("Restore"); restoreBtn.addActionListener(this); restoreBtnPnl.add(restoreBtn); buttonsPnl.add(restoreBtnPnl,BorderLayout.WEST); buttonsPnl.add(okCancelPnl,BorderLayout.EAST); mainPnl.add(buttonsPnl,BorderLayout.SOUTH); pack(); } /** * Build the widgets shown in the dialog */ private void buildWidgets() { // NUM OF LOGS maxLogsInTableCB.setEditable(false); maxLogsInTableCB.setMaximumRowCount(NumberOption.values().length); // TIME FRAME timeFrameCB.setEditable(false); timeFrameCB.setMaximumRowCount(TimeOption.values().length); // INPUT RATE inputRateTF.setInputVerifier(new PassVerifier(1)); // OUTPUT RATE outputRateTF.setInputVerifier(new PassVerifier(1)); // THRESHOLD dynThresholdTF.setInputVerifier(new PassVerifier(1024)); dynDampingTF.setInputVerifier(new PassVerifier(0)); dynIntervalTF.setInputVerifier(new PassVerifier(1)); // Add the listener to the check boxes for (OptionWidgets widget: OptionWidgets.values()) { widget.enableCB.addActionListener(this); } } /** * Ratio the content of the widgets getting their values from * <code>preferences</code>. * * * @param numbOfLogs The number of logs * @param timeFrame The number of minutes of the time frame * * @see prefrences */ private void ratioWidgets() { // Set the max num of logs NumberOption nOpt = NumberOption.fromInt(preferences.getMaxNumOfLogs()); if (nOpt==null) { maxLogsInTableCB.setSelectedIndex(2); } else { maxLogsInTableCB.setSelectedIndex(nOpt.ordinal()); } OptionWidgets.MAX_NUM_OF_LOGS.enableCB.setSelected(maxLogsInTableCB.getSelectedIndex()!=0); // Set the time frame TimeOption tOpt = TimeOption.fromInt(preferences.getMinuteTimeFrame()); if (tOpt==null) { timeFrameCB.setSelectedIndex(0); } else { timeFrameCB.setSelectedIndex(tOpt.ordinal()); } OptionWidgets.TIME_FRAME.enableCB.setSelected(timeFrameCB.getSelectedIndex()!=0); if (preferences.getMaxInputRate()==Integer.MAX_VALUE) { inputRateTF.setText("0"); } else { inputRateTF.setText(""+preferences.getMaxInputRate()); } OptionWidgets.MAX_INPUT_RATE.enableCB.setSelected(preferences.getMaxInputRate()!=Integer.MAX_VALUE); if (preferences.getMaxOutputRate()==Integer.MAX_VALUE) { outputRateTF.setText("0"); } else { outputRateTF.setText(""+preferences.getMaxOutputRate()); } OptionWidgets.MAX_OUTPUT_RATE.enableCB.setSelected(preferences.getMaxOutputRate()!=Integer.MAX_VALUE); if (preferences.getDynThreshold()==Integer.MAX_VALUE) { dynThresholdTF.setText("8192"); dynDampingTF.setText("2048"); dynIntervalTF.setText("30"); } OptionWidgets.DYNAMIC_DISCARD_LEVEL.enableCB.setSelected(preferences.getDynThreshold()!=Integer.MAX_VALUE); for (OptionWidgets opt: OptionWidgets.values()) { enableOption(opt.enableCB); } } /** * Enable or disable the option of the given check box. * * @param cB The chackbox the enable/disable the option */ private void enableOption(JCheckBox cB) { if (cB==null) { throw new IllegalArgumentException("The JCheckBox can't be null"); } OptionWidgets opt = OptionWidgets.fromCheckBox(cB); switch (opt) { case MAX_NUM_OF_LOGS: maxLogsInTableCB.setEnabled(cB.isSelected()); break; case TIME_FRAME: timeFrameCB.setEnabled(cB.isSelected()); break; case MAX_INPUT_RATE: inputRateTF.setEnabled(cB.isSelected()); break; case MAX_OUTPUT_RATE: outputRateTF.setEnabled(cB.isSelected()); break; case DYNAMIC_DISCARD_LEVEL: dynThresholdTF.setEnabled(cB.isSelected()); dynDampingTF.setEnabled(cB.isSelected()); dynIntervalTF.setEnabled(cB.isSelected()); break; } } /** * Return true if the user pressed the Ok button * to approve the changes * */ public boolean okPressed() { return okBtnPressed; } /** * Return the user preferences defined in the dialog. * * @return The user preferences defined in the dialog. * @see preferences */ public UserPreferences getPreferences() { // Put the values in the GUI into preferences if (OptionWidgets.MAX_NUM_OF_LOGS.isOptionEnabled()) { System.out.println("A"); NumberOption opt = (NumberOption)maxLogsInTableCB.getSelectedItem(); preferences.setMaxLogs(opt.value); } else { System.out.println("B"); preferences.setMaxLogs(0); } if (OptionWidgets.TIME_FRAME.isOptionEnabled()) { TimeOption opt = (TimeOption)timeFrameCB.getSelectedItem(); preferences.setTimeFrame(opt.value); } else { preferences.setTimeFrame(0); } if (OptionWidgets.MAX_INPUT_RATE.isOptionEnabled()) { String val = inputRateTF.getText(); preferences.setMaxInputRate(Integer.parseInt(val)); } else { preferences.setMaxInputRate(Integer.MAX_VALUE); } if (OptionWidgets.MAX_OUTPUT_RATE.isOptionEnabled()) { String val = outputRateTF.getText(); preferences.setMaxOutputRate(Integer.parseInt(val)); } else { preferences.setMaxOutputRate(Integer.MAX_VALUE); } if (OptionWidgets.DYNAMIC_DISCARD_LEVEL.isOptionEnabled()) { preferences.setDynThreshold(Integer.parseInt(dynThresholdTF.getText())); preferences.setDynDamping(Integer.parseInt(dynDampingTF.getText())); preferences.setDynTime(Integer.parseInt(dynIntervalTF.getText())); } else { preferences.setDynThreshold(Integer.MAX_VALUE); preferences.setDynDamping(0); preferences.setDynTime(30); } return preferences; } /** * Override <code>JDialog.setVisible</code> to show this dialog over * the <code>LogsingClient</code> component. */ @Override public void setVisible(boolean visible) { setLocationRelativeTo(owner); pack(); super.setVisible(visible); toFront(); } }