All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.googlecode.blaisemath.firestarter.property.PropertySheet Maven / Gradle / Ivy

Go to download

Provides editors for various Java bean object types, and a generic, customizable PropertySheet.

The newest version!
package com.googlecode.blaisemath.firestarter.property;

/*
 * #%L
 * Firestarter
 * --
 * Copyright (C) 2009 - 2024 Elisha Peterson
 * --
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.beans.PropertyChangeListener;
import javax.swing.AbstractCellEditor;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

/**
 * Table used for editing a collection of key-value properties.
 *
 * @author Elisha Peterson
 */
public class PropertySheet extends JPanel {

    /** This static variable determines whether the filter panel is on or off by default. */
    static boolean TOOLBAR_VISIBLE_DEFAULT = false;
    /** Determines minimum height of cells in the table. */
    private static final int MIN_CELL_HEIGHT = 20;
    /** Minimum cell width */
    private static final int MIN_CELL_WIDTH = 40;
    /** Maximum width of a cell */
    private static final int MAX_CELL_WIDTH = 400;
    /** Preferred width for custom editor buttons. */
    private static final int PREF_BUTTON_WIDTH = 100;

    /** Default width of first column */
    protected int defaultNameColWidth = 70;

    /** The table displayed. */
    protected JTable table;
    /** Flag for showing/hiding extra panels */
    protected boolean toolsVisible = TOOLBAR_VISIBLE_DEFAULT;
    /** The panel with the filter box. */
    protected JPanel toolPanel;
    /** The combo box for filtering. */
    protected JComboBox filterCombo;
    /** The underlying table model. */
    protected PropertySheetModel model;

    /** Initialize sheet with an empty model. */
    public PropertySheet() {
        initComponents(new PropertyModel.Empty());
    }
    
    /**
     * Initialize sheet with specified model.
     * @param pm property model for editing
     */
    public PropertySheet(PropertyModel pm) {
        initComponents(pm);
    }
    
    /**
     * Create a property sheet that uses the supplied bean object for editing components.
     * @param bean a bean object
     * @return new property sheet for editing the bean's properties
     */
    public static PropertySheet forBean(Object bean) {
        PropertySheet res = new PropertySheet();
        res.initComponents(new BeanPropertyModel(bean));
        return res;
    }
    
    /**
     * Create a property sheet with a custom model
     * @param model property model
     * @return property sheet
     */
    public static PropertySheet forModel(PropertyModel model) {
        return new PropertySheet(model);
    }

    //region INITIALIZATION

    protected final void initComponents(PropertyModel model) {
        initTable(model);
        initToolbar();

        setLayout(new BorderLayout());
        add(table, BorderLayout.CENTER);
        if (toolsVisible) {
            add(toolPanel, BorderLayout.NORTH);
        }
    }
    
    /**
     * Initialize table, setting up components, column sizes, etc.
     * @param pm property model
     */
    protected void initTable(PropertyModel pm) {
        table = new JTable();
        Color fg = UIManager.getColor("Label.foreground");
        Color bg = UIManager.getColor("Label.background");
        table.setGridColor(new Color(
                (fg.getRed() + 5 * bg.getRed()) / 6,
                (fg.getGreen() + 5 * bg.getGreen()) / 6,
                (fg.getBlue() + 5 * bg.getBlue()) / 6));
        model = new PropertySheetModel(new PropertyEditorModel(pm));
        model.addTableModelListener(e -> handleTableChange());
        table.setModel(model);
        table.getTableHeader().setReorderingAllowed(false);
        updateRowHeights();

        TableColumn column = table.getColumnModel().getColumn(1);
        column.setCellRenderer(new ValueColEditor());
        column.setCellEditor(new ValueColEditor());

        // set up column sizes
        for (int col = 0; col < 2; col++) {
            int prefWidth = MIN_CELL_WIDTH;
            for (int row = 0; row < model.getRowCount(); row++) {
                Object val = model.getValueAt(row, col);
                Component comp = table.getCellRenderer(row, col)
                        .getTableCellRendererComponent(table, val, false, false, row, col);
                int wid = comp instanceof DefaultPropertyComponent
                        ? PREF_BUTTON_WIDTH
                        : comp.getPreferredSize().width;
                prefWidth = Math.max(prefWidth, wid);
            }
            prefWidth = Math.min(prefWidth, MAX_CELL_WIDTH);
            table.getColumnModel().getColumn(col).setPreferredWidth(prefWidth);
            if (col == 0) {
                table.getColumnModel().getColumn(col).setMinWidth(Math.min(prefWidth, MIN_CELL_WIDTH));
            }
        }
    }
    
    protected void initToolbar() {
        // set up filter
        filterCombo = new JComboBox<>(new DefaultComboBoxModel<>(BeanPropertyFilter.values()));
        Font font = filterCombo.getFont().deriveFont((float) filterCombo.getFont().getSize() - 2);
        filterCombo.setFont(font);
        filterCombo.setSelectedItem(BeanPropertyFilter.STANDARD);
        filterCombo.addActionListener(e -> {
            if (getPropertyModel() instanceof BeanPropertyModel) {
                ((BeanPropertyModel) getPropertyModel()).setFilter(
                        (BeanPropertyFilter) filterCombo.getSelectedItem());
            }
        });

        JLabel filterLabel = new JLabel("Filter: ");
        filterLabel.setFont(font.deriveFont(Font.ITALIC));
        filterLabel.setOpaque(false);

        toolPanel = new JPanel();
        toolPanel.setLayout(new BoxLayout(toolPanel, BoxLayout.LINE_AXIS));
        toolPanel.setBackground(table.getGridColor());
        toolPanel.add(Box.createGlue());
        toolPanel.add(filterLabel);
        toolPanel.add(filterCombo);
    }

    //endregion
    
    /** 
     * Get the core property model used by the property sheet.
     * @return property model
     */
    public PropertyModel getPropertyModel() {
        return model.getPropertyModel();
    }

    /** 
     * Return toolbar status.
     * @return true if toolbar is visible 
     */
    public boolean isToolbarVisible() {
        return toolsVisible;
    }
    
    /** 
     * Sets toolbar visibility
     * @param val true if visible
     */
    public void setToolbarVisible(boolean val) {
        if (val != toolsVisible) {
            toolsVisible = val;
            if (val) {
                add(toolPanel, BorderLayout.NORTH);
            } else {
                remove(toolPanel);
            }
            validate();
        }
    }

    //region EVENT HANDLING

    public void removeBeanChangeListener(PropertyChangeListener listener) {
        getPropertyModel().removePropertyChangeListener(listener);
    }

    public void removeBeanChangeListener(String propertyName, PropertyChangeListener listener) {
        getPropertyModel().removePropertyChangeListener(propertyName, listener);
    }

    public void addBeanChangeListener(PropertyChangeListener listener) {
        getPropertyModel().addPropertyChangeListener(listener);
    }

    public void addBeanChangeListener(String propertyName, PropertyChangeListener listener) {
        getPropertyModel().addPropertyChangeListener(propertyName, listener);
    }

    /**
     * Update row heights when the underlying data changes.
     */
    protected void handleTableChange() {
        table.getSelectionModel().clearSelection();
        if (table.getCellEditor() != null) {
            table.getCellEditor().stopCellEditing();
        }
        updateRowHeights();
        firePropertyChange("size", null, null);
        repaint();
    }

    /** Updates the size of the table. */
    void updateRowHeights() {
        Component comp;
        for (int i = 0; i < model.getRowCount(); i++) {
            comp = model.getPropertyEditorModel().getElementAt(i);
            if (comp != null) {
                table.setRowHeight(i, Math.max(comp.getPreferredSize().height, MIN_CELL_HEIGHT));
            }
        }
        table.setPreferredScrollableViewportSize(new Dimension(
                getPreferredSize().width,
                getPreferredSize().height + (table.getTableHeader() != null ? table.getTableHeader().getHeight() : 0)));
    }

    //endregion
    
    //region INNER CLASSES

    /** Provides support for editing properties. */
    class ValueColEditor extends AbstractCellEditor implements TableCellEditor, TableCellRenderer {
        /** Current row being edited. */
        int row = -1;

        @Override
        public Object getCellEditorValue() {
            return row == -1 ? null : getPropertyModel().getPropertyValue(row);
        }

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            this.row = row;
            return model.getPropertyEditorModel().getElementAt(row);
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            return model.getPropertyEditorModel().getElementAt(row);
        }
    }
    
    //endregion
    
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy