com.eviware.soapui.support.components.JPropertiesTable.java Source code

Java tutorial

Introduction

Here is the source code for com.eviware.soapui.support.components.JPropertiesTable.java

Source

/*
 *  soapUI, copyright (C) 2004-2011 smartbear.com 
 *
 *  soapUI is free software; you can redistribute it and/or modify it under the 
 *  terms of version 2.1 of the GNU Lesser General Public License as published by 
 *  the Free Software Foundation.
 *
 *  soapUI 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 at gnu.org.
 */

package com.eviware.soapui.support.components;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.datatransfer.StringSelection;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableModel;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

import com.eviware.soapui.SoapUI;
import com.eviware.soapui.support.PropertyChangeNotifier;
import com.eviware.soapui.support.StringUtils;

/**
 * Table for displaying property name/value pairs
 * 
 * @author Ole.Matzura
 */

@SuppressWarnings("serial")
public class JPropertiesTable<T> extends JPanel {
    public final static Object[] BOOLEAN_OPTIONS = new Object[] { Boolean.TRUE, Boolean.FALSE };

    private PropertiesTableModel<T> tableModel;
    private JTable table;

    private TitledBorder titledBorder;

    private String title;

    public JPropertiesTable(String title) {
        this(title, null);
    }

    public JPropertiesTable(String title, T propertyObject) {
        super(new BorderLayout());
        this.title = title;

        tableModel = new PropertiesTableModel<T>(propertyObject);
        table = new PTable(tableModel);

        table.getColumnModel().getColumn(0).setHeaderValue("Property");
        table.getColumnModel().getColumn(1).setHeaderValue("Value");
        table.getColumnModel().getColumn(0).setCellRenderer(new PropertiesTableCellRenderer());
        table.getColumnModel().getColumn(1).setCellRenderer(new PropertiesTableCellRenderer());

        add(new JScrollPane(table), BorderLayout.CENTER);
        titledBorder = BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), title);
        /*
         * Java 7 issue
         * 
         * old: titledBorder.setTitleFont( titledBorder.getTitleFont().deriveFont(
         * Font.PLAIN, 11 ) ); titledBorder.getTitleFont() return null in Java 7
         */
        Font defaultUIFont = getUIDefaultFont();
        if (defaultUIFont != null)
            titledBorder.setTitleFont(getUIDefaultFont().deriveFont(Font.PLAIN, 11));

        if (title != null)
            setBorder(titledBorder);

        table.setBackground(Color.WHITE);
        setPreferredSize(table.getPreferredSize());
    }

    private Font getUIDefaultFont() {
        UIDefaults uidefs = UIManager.getLookAndFeelDefaults();
        for (Object key : uidefs.keySet()) {
            if (uidefs.get(key) instanceof Font) {
                return uidefs.getFont(key);
            }
        }
        return null;
    }

    public void setTitle(String title) {
        this.title = title;
        titledBorder.setTitle(title);
        setBorder(titledBorder);
        repaint();
    }

    public String getTitle() {
        return title;
    }

    @Override
    public void removeNotify() {
        getTableModel().release();
        super.removeNotify();
    }

    @Override
    public void addNotify() {
        getTableModel().attach();
        super.addNotify();
    }

    public void setPropertyObject(T propertyObject) {
        if (table.isEditing())
            table.getCellEditor().stopCellEditing();

        tableModel.setPropertyObject(propertyObject);
    }

    public PropertiesTableModel<?> getTableModel() {
        return tableModel;
    }

    public PropertyDescriptor addProperty(String caption, String name) {
        return addProperty(caption, name, false);
    }

    public PropertyDescriptor addProperty(String caption, String name, boolean editable) {
        return addProperty(caption, name, editable, null);
    }

    public PropertyDescriptor addProperty(String caption, String name, boolean editable,
            PropertyFormatter formatter) {
        return tableModel.addProperty(caption, name, editable, formatter);
    }

    public static final class PropertiesTableModel<T> extends AbstractTableModel implements PropertyChangeListener {
        private List<PropertyDescriptor> properties = new ArrayList<PropertyDescriptor>();
        private T propertyObject;
        private boolean attached;

        public PropertiesTableModel(T propertyObject) {
            this.propertyObject = propertyObject;
        }

        public void attach() {
            if (!attached && propertyObject instanceof PropertyChangeNotifier) {
                ((PropertyChangeNotifier) propertyObject).addPropertyChangeListener(this);
                attached = true;
            }
        }

        public void setPropertyObject(T propertyObject) {
            release();
            this.propertyObject = propertyObject;
            attach();
            fireTableDataChanged();
        }

        public PropertyDescriptor addProperty(String caption, String name, boolean editable,
                PropertyFormatter formatter) {
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(caption, name, editable, formatter);
            properties.add(propertyDescriptor);
            return propertyDescriptor;
        }

        public PropertyDescriptor addProperty(String caption, String name, Object[] options) {
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(caption, name, options);
            properties.add(propertyDescriptor);
            return propertyDescriptor;
        }

        public int getRowCount() {
            return properties.size();
        }

        public int getColumnCount() {
            return 2;
        }

        public boolean isCellEditable(int rowIndex, int columnIndex) {
            if (columnIndex == 0 || propertyObject == null)
                return false;
            return properties.get(rowIndex).isEditable()
                    && PropertyUtils.isWriteable(propertyObject, properties.get(rowIndex).getName());
        }

        public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
            try {
                if (propertyObject != null && columnIndex == 1 && properties.get(rowIndex).isEditable()) {
                    BeanUtils.setProperty(propertyObject, properties.get(rowIndex).getName(), aValue);
                }
            } catch (IllegalAccessException e) {
                SoapUI.logError(e);
            } catch (InvocationTargetException e) {
                SoapUI.logError(e);
            }
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            if (propertyObject == null)
                return null;

            try {
                PropertyDescriptor propertyDescriptor = properties.get(rowIndex);
                switch (columnIndex) {
                case 0:
                    return propertyDescriptor.getCaption();
                case 1: {
                    Object value = PropertyUtils.getSimpleProperty(propertyObject, propertyDescriptor.getName());
                    return propertyDescriptor.getFormatter().format(propertyDescriptor.getName(), value);
                }
                }
            } catch (IllegalAccessException e) {
                SoapUI.logError(e);
            } catch (InvocationTargetException e) {
                SoapUI.logError(e);
            } catch (NoSuchMethodException e) {
                SoapUI.logError(e);
            }

            return null;
        }

        public PropertyDescriptor getPropertyDescriptorAt(int row) {
            return properties.get(row);
        }

        public void propertyChange(PropertyChangeEvent evt) {
            fireTableDataChanged();
        }

        public void release() {
            if (propertyObject instanceof PropertyChangeNotifier && attached) {
                ((PropertyChangeNotifier) propertyObject).removePropertyChangeListener(this);
                attached = false;
            }
        }

        public PropertyDescriptor addPropertyShadow(String caption, String name, boolean editable) {
            PropertyDescriptor propertyDescriptor = new PropertyDescriptor(caption, name, editable);
            properties.add(propertyDescriptor);
            return propertyDescriptor;
        }
    }

    public static class PropertyDescriptor {
        private final String caption;
        private final String name;
        private boolean editable;
        private PropertyFormatter formatter;
        private Object[] options;
        private DefaultCellEditor cellEditor;
        private String description;

        public PropertyDescriptor(String caption, String name, boolean editable, PropertyFormatter formatter) {
            this.caption = caption;
            this.name = name;
            this.editable = editable;
            this.formatter = formatter;

            JTextField textField = new JTextField();
            textField.setBorder(BorderFactory.createEmptyBorder());
            cellEditor = new DefaultCellEditor(textField);
        }

        public PropertyDescriptor(String caption, String name, Object[] options) {
            this.caption = caption;
            this.name = name;
            this.options = options;
            editable = true;

            JComboBox comboBox = new JComboBox(options);

            if (options.length > 0 && options[0] == null) {
                comboBox.setEditable(true);
                comboBox.removeItemAt(0);
            }

            comboBox.setBorder(null);
            cellEditor = new DefaultCellEditor(comboBox);
        }

        /**
         * For password field in table.
         * 
         * @author robert nemet
         * @param caption
         * @param name
         * @param editable
         */
        public PropertyDescriptor(String caption, String name, boolean editable) {

            this.caption = caption;
            this.name = name;
            this.editable = editable;

            JPasswordField textField = new JPasswordField();
            textField.setBorder(BorderFactory.createEmptyBorder());
            cellEditor = new DefaultCellEditor(textField);
        }

        public void setFormatter(PropertyFormatter formatter) {
            this.formatter = formatter;
        }

        public PropertyFormatter getFormatter() {
            return formatter == null ? DefaultFormatter.getInstance() : formatter;
        }

        public String getCaption() {
            return caption;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public boolean isEditable() {
            return editable;
        }

        public Object[] getOptions() {
            return options;
        }

        public boolean hasOptions() {
            return options != null;
        }

        public String getName() {
            return name;
        }

        public TableCellEditor getCellEditor() {
            return cellEditor;
        }
    }

    private static class PropertiesTableCellRenderer extends DefaultTableCellRenderer {
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                boolean hasFocus, int row, int column) {
            Component component;
            DefaultCellEditor cellEditor = (DefaultCellEditor) table.getCellEditor(row, column);
            if (cellEditor.getComponent() instanceof JPasswordField && value instanceof String) {
                if (value != null && ((String) value).length() > 0) {
                    component = super.getTableCellRendererComponent(table, "**************", isSelected, hasFocus,
                            row, column);
                } else {
                    component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
                            column);
                }
            } else {
                component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
            if (component instanceof JComponent) {
                PropertyDescriptor descriptor = ((PropertiesTableModel<?>) table.getModel())
                        .getPropertyDescriptorAt(row);

                if (StringUtils.hasContent(descriptor.getDescription())) {
                    ((JComponent) component).setToolTipText(descriptor.getDescription());
                }
                // do not set tooltip as value for password field, it has no sense.
                else if (value != null && StringUtils.hasContent(value.toString())
                        && !(cellEditor.getComponent() instanceof JPasswordField)) {
                    ((JComponent) component).setToolTipText(value.toString());
                } else {
                    ((JComponent) component).setToolTipText(null);
                }
            }

            return component;
        }
    }

    /*
     * defaultcelleditor private class PropertiesTableCellEditor extends
     * AbstractCellEditor implements TableCellEditor { private JTextField
     * textField; private JComboBox comboBox; private JComponent current;
     * 
     * public PropertiesTableCellEditor() { textField = new JTextField();
     * comboBox = new JComboBox();
     * comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE); }
     * 
     * public Component getTableCellEditorComponent(JTable table, Object value,
     * boolean isSelected, int row, int column) { PropertyDescriptor descriptor =
     * tableModel.getPropertyDescriptorAt( row );
     * 
     * if( descriptor.hasOptions()) { comboBox.setModel( new
     * DefaultComboBoxModel( descriptor.getOptions() ));
     * comboBox.setSelectedItem( value ); current = comboBox; } else {
     * textField.setText( value == null ? "" : value.toString() ); current =
     * textField; }
     * 
     * current.setBorder( null ); current.setBackground( Color.WHITE );
     * 
     * return current; }
     * 
     * public Object getCellEditorValue() { return current == comboBox ?
     * comboBox.getSelectedItem() : textField.getText(); } }
     */

    /**
     * Formatter used for displaying property values
     * 
     * @author Ole.Matzura
     */

    public interface PropertyFormatter {
        public Object format(String propertyName, Object value);
    }

    private static class DefaultFormatter implements PropertyFormatter {
        private static PropertyFormatter instance;

        public static PropertyFormatter getInstance() {
            if (instance == null)
                instance = new DefaultFormatter();

            return instance;
        }

        public Object format(String propertyName, Object value) {
            return value;
        }
    }

    public PropertyDescriptor addProperty(String caption, String name, Object[] options) {
        return tableModel.addProperty(caption, name, options);
    }

    private class PTable extends JTable {
        public PTable(TableModel tableModel) {
            super(tableModel);

            // setAutoStartEditOnKeyStroke( true );

            getActionMap().put(TransferHandler.getCopyAction().getValue(Action.NAME), new AbstractAction() {
                public void actionPerformed(ActionEvent e) {
                    int row = getSelectedRow();
                    if (row == -1)
                        return;

                    StringSelection selection = new StringSelection(getValueAt(row, 1).toString());
                    Toolkit.getDefaultToolkit().getSystemClipboard().setContents(selection, selection);
                }
            });

            putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
            /*
             * addFocusListener( new FocusAdapter() {
             * 
             * public void focusLost(FocusEvent e) { if( isEditing() &&
             * getCellEditor() != null ) getCellEditor().stopCellEditing(); }} );
             */
        }

        public TableCellEditor getCellEditor(int row, int column) {
            if (column == 0)
                return super.getCellEditor(row, column);
            else
                return tableModel.getPropertyDescriptorAt(row).getCellEditor();
        }
    }

    /**
     * Value in this field will not be showen. It will be masked...
     * 
     * @author robert nemet
     * @param caption
     * @param name
     * @param editable
     * @return
     */
    public PropertyDescriptor addPropertyShadow(String caption, String name, boolean editable) {
        return tableModel.addPropertyShadow(caption, name, editable);
    }
}