package open.dolphin.project; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.beans.PropertyDescriptor; import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JSpinner; import javax.swing.JTextField; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.DocumentListener; import open.dolphin.client.ClientContext; /** * AbstractPropertySheet * * @author Kazushi Minagawa, Digital Globe, Inc. * @author s.oh^ */ public abstract class AbstractPropertySheet { public static final String STATE_PROP = "stateProp"; public enum State {NONE_STATE,VALID_STATE,INVALID_STATE}; private static final int UI_WIDTH_MIN = 10; private static final int UI_HEIGHT_MIN = 10; private ProjectSettingDialog context; private ProjectStub projectStub; private PropertyChangeSupport boundSupport; protected AbstractPropertySheet.State state = AbstractPropertySheet.State.NONE_STATE; private JPanel ui; private boolean loginState; private String title; private String icon; private String id; /** * Creates a new instance of AbstractPropertySheet */ public AbstractPropertySheet() { ui = new JPanel(); } public String getId() { return id; } public void setId(String id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getIcon() { return icon; } public void setIcon(String icon) { this.icon = icon; } public ProjectSettingDialog getContext() { return context; } public void setContext(ProjectSettingDialog context) { this.context = context; this.addPropertyChangeListener(STATE_PROP, context); this.setLogInState(context.getLoginState()); } public boolean isLoginState() { return loginState; } public void setLogInState(boolean login) { loginState = login; } public JPanel getUI() { return ui; } public void setUI(JPanel p) { ui = p; if(ui != null) { ui.setMinimumSize(new Dimension(UI_WIDTH_MIN, UI_HEIGHT_MIN)); } } public abstract void start(); public abstract void save(); public void addPropertyChangeListener(String prop, PropertyChangeListener l) { if (boundSupport == null) { boundSupport = new PropertyChangeSupport(this); } boundSupport.addPropertyChangeListener(prop, l); } public void removePropertyChangeListener(String prop, PropertyChangeListener l) { if (boundSupport == null) { boundSupport = new PropertyChangeSupport(this); } boundSupport.removePropertyChangeListener(prop, l); } public ProjectStub getProjectStub() { return projectStub; } public void setProjectStub(ProjectStub projectStub) { this.projectStub = projectStub; } protected void setState(AbstractPropertySheet.State state) { AbstractPropertySheet.State old = this.state; this.state = state; if (this.state!=old) { boundSupport.firePropertyChange(STATE_PROP, null, this.state); } } protected AbstractPropertySheet.State getState() { return state; } /** * courtesy of * http://www.sable.mcgill.ca/~hendren/303/BookSlides/Ch7/code/propedit/PropertySheet.java.html * Gets the property editor for a given property, * and wires it so that it updates the given object. * @param bean the object whose properties are being edited * @param descriptor the descriptor of the property to * be edited * @return a property editor that edits the property * with the given descriptor and updates the given object */ public PropertyEditor getEditor(final SettingBean bean, PropertyDescriptor descriptor) { try { // Getter Method getter = descriptor.getReadMethod(); if (getter == null) { return null; } // Setter final Method setter = descriptor.getWriteMethod(); if (setter == null) { return null; } final PropertyEditor editor; Class editorClass = descriptor.getPropertyEditorClass(); if (editorClass != null) { editor = (PropertyEditor) editorClass.newInstance(); } else { editor = PropertyEditorManager.findEditor(descriptor.getPropertyType()); } if (editor == null) { return null; } // Set editor beans' value Object value = getter.invoke(bean, new Object[] {}); editor.setValue(value); return editor; } catch (InstantiationException | IllegalAccessException | InvocationTargetException exception) { return null; } } /** * courtesy of * http://www.sable.mcgill.ca/~hendren/303/BookSlides/Ch7/code/propedit/PropertySheet.java.html * Wraps a property editor into a component. * @param editor the editor to wrap * @return a button (if there is a custom editor), * combo box (if the editor has tags), or text field (otherwise) */ public Component getEditorComponent(final SettingBean bean, final PropertyEditor editor, PropertyDescriptor pd) { String[] tags = editor.getTags(); String text = editor.getAsText(); Method setter = pd.getWriteMethod(); //minagawa^ if (editor instanceof DecimalEditorSupport) { final JTextField textField = new JTextField(text, 3); textField.setHorizontalAlignment(SwingConstants.RIGHT); textField.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(javax.swing.event.DocumentEvent e) { try { editor.setAsText(textField.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); } catch (IllegalArgumentException exception) { } } @Override public void removeUpdate(javax.swing.event.DocumentEvent e) { try { editor.setAsText(textField.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); } catch (IllegalArgumentException exception) { } } @Override public void changedUpdate(javax.swing.event.DocumentEvent e) { } }); JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); panel.add(textField); return panel; } else if (editor instanceof SpinnerEditorSupport) { SpinnerEditorSupport spinnerEditor = (SpinnerEditorSupport)editor; SpinnerModel fetchModel = new SpinnerNumberModel((Integer)editor.getValue(), new Integer(spinnerEditor.getMinValue()), new Integer(spinnerEditor.getMaxValue()), new Integer(spinnerEditor.getStepValue())); JSpinner spinner = new JSpinner(fetchModel); spinner.setEditor(new JSpinner.NumberEditor(spinner, "#")); spinner.addChangeListener((ChangeEvent e) -> { JSpinner spn = (JSpinner)e.getSource(); editor.setAsText(spn.getValue().toString()); setBeanValue(bean, setter, editor.getValue()); }); JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); panel.add(spinner); return panel; } else if (editor instanceof DirectoryEditorSupport) { final JTextField textField = new JTextField(text, 15); textField.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(javax.swing.event.DocumentEvent e) { try { editor.setAsText(textField.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); } catch (IllegalArgumentException exception) { } } @Override public void removeUpdate(javax.swing.event.DocumentEvent e) { try { editor.setAsText(textField.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); } catch (IllegalArgumentException exception) { } } @Override public void changedUpdate(javax.swing.event.DocumentEvent e) { } }); java.util.ResourceBundle bundle = ClientContext.getMyBundle(AbstractPropertySheet.class); JButton choose = new JButton(bundle.getString("ChooseButton")); choose.addActionListener((ActionEvent e) -> { JFileChooser chooser = new JFileChooser(); chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int returnVal = chooser.showOpenDialog(null); if (returnVal == JFileChooser.APPROVE_OPTION) { String dir = chooser.getSelectedFile().getPath(); textField.setText(dir); editor.setAsText(textField.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); } }); JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); panel.add(textField); panel.add(choose); return panel; } //minagawa$ else if (tags!=null) { if (tags.length==1) { // make checkbox that shows a tag final JCheckBox chk = new JCheckBox(pd.getDisplayName()); chk.setSelected(Boolean.parseBoolean(text)); chk.addActionListener((ActionEvent e) -> { JCheckBox box = (JCheckBox)e.getSource(); editor.setAsText(String.valueOf(box.isSelected())); setBeanValue(bean, setter, editor.getValue()); check(bean); }); return chk; } else if (tags.length<=3) { // make radio buttons that shows all tag final ButtonGroup group = new ButtonGroup(); JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); JRadioButton toCheck=null; for (String name : tags) { JRadioButton rd = new JRadioButton(name); group.add(rd); panel.add(rd); if (name.equals(text)) { toCheck = rd; } rd.addActionListener((ActionEvent e) -> { JRadioButton r = (JRadioButton)e.getSource(); editor.setAsText(r.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); }); } if (toCheck!=null) { toCheck.setSelected(true); } return panel; } else { // make a combo box that shows all tags final JComboBox comboBox = new JComboBox(tags); comboBox.setSelectedItem(text); comboBox.addItemListener((ItemEvent event) -> { if (event.getStateChange() == ItemEvent.SELECTED) { editor.setAsText((String) comboBox.getSelectedItem()); setBeanValue(bean, setter, editor.getValue()); check(bean); } }); JPanel ret = new JPanel(new FlowLayout(FlowLayout.LEFT)); ret.add(comboBox); return ret; } } else { final JTextField textField = new JTextField(text, 10); textField.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(javax.swing.event.DocumentEvent e) { try { editor.setAsText(textField.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); } catch (IllegalArgumentException exception) { } } @Override public void removeUpdate(javax.swing.event.DocumentEvent e) { try { editor.setAsText(textField.getText()); setBeanValue(bean, setter, editor.getValue()); check(bean); } catch (IllegalArgumentException exception) { } } @Override public void changedUpdate(javax.swing.event.DocumentEvent e) { } }); return textField; } } private void setBeanValue(final Object bean, Method setter, Object value) { try { setter.invoke(bean, new Object[]{value}); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { Logger.getLogger(ConnectionPropertySheet.class.getName()).log(Level.SEVERE, null, ex); } } protected void check(SettingBean bean) { AbstractPropertySheet.State newState = bean.isValidBean() ? AbstractPropertySheet.State.VALID_STATE : AbstractPropertySheet.State.INVALID_STATE; setState(newState); } }