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

com.lyonesgamer.propertygrid.properties.FontProperty Maven / Gradle / Ivy

The newest version!
package com.lyonesgamer.propertygrid.properties;

import com.lyonesgamer.propertygrid.PGProperty;

import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;

/**
 * Represents a font, either system or custom.
 *
 * @author Tristan Patch
 * @since 1.0
 */
public class FontProperty extends PGProperty {

    /**
     * The current value of the property.
     */
    protected Font value;

    /**
     * An array of all the fonts installed on this system. Cached here for quick access.
     */
    protected static Font[] systemFonts;

    /**
     * The editor to use.
     */
    protected FontEditor editor = new FontEditor();

    /**
     * The renderer to use.
     */
    protected FontRenderer renderer = new FontRenderer();

    static {
        GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
        Font[] fonts = env.getAllFonts();
        systemFonts = new Font[fonts.length];
        for (int i = 0; i < fonts.length; i++)
            systemFonts[i] = fonts[i].deriveFont(12.f);
    }

    /**
     * Creates a new property.
     *
     * @param name The name of the property in the grid.
     * @param value The initial value of the property.
     */
    public FontProperty(String name, Font value) {
        super(name);

        this.value = value;
    }

    @Override
    protected void doAfterAdded() {}

    /**
     * Validates the property. Until a better scheme can be decided, determines if the font is capable of displaying
     * the sentence "the quick brown fox jumps over the lazy dog", which contains all English letters. The problem with
     * this is it would mark CJK fonts as invalid.
     *
     * @param value The value to be validated.
     * @return If the property is valid according to these rules.
     */
    @Override
    public boolean onValidateValue(Font value) {
        return value.canDisplayUpTo("the quick brown fox jumps over the lazy dog") == -1;
    }

    @Override
    public void onSetValue(Font value) {
        if (parent != null)
            parent.firePropertyChangeEvent(this, value);
        this.value = value;
    }

    /**
     * Attempts to decode the value as a font (using {@link Font#decode(String)}). If this fails, attempts to read the font
     * as a filename.
     *
     * @param value The string to attempt to set from.
     */
    @Override
    public void setValueFromString(String value) {
        Font f = Font.decode(value);
        if (value.contains(f.getFontName()) || f.getFontName().contains(value))
            setValue(f);
        else {
            try {
                setValue(Font.createFont(Font.PLAIN, new File(value)).deriveFont(12.f));
            } catch (FontFormatException | IOException ignored) {
            }
        }
    }

    @Override
    public void setValueFromLong(long value) {}

    @Override
    public Font getValue() {
        return value;
    }

    /**
     * Attempts to decode the value as a font (using {@link Font#decode(String)}). If this fails, attempts to read the font
     * as a filename.
     *
     * @param value The string to attempt to set from.
     */
    @Override
    public Font stringToValue(String value) {
        Font f = Font.decode(value);
        if (value.contains(f.getFontName()) || f.getFontName().contains(value))
            return f;
        else {
            try {
                return Font.createFont(Font.PLAIN, new File(value));
            } catch (FontFormatException | IOException e) {
                return null;
            }
        }
    }

    /**
     * Not implemented.
     *
     * @param value The value to convert to a value type of this property.
     * @return An empty Optional.
     */
    @Override
    public Font longToValue(long value) {
        return null;
    }

    /**
     * If the value is a valid font, returns the system name of the font.
     *
     * @param value The value to convert.
     * @return The name of the font, or an empty string if invalid.
     */
    @Override
    public String valueToString(Font value) {
        if (value == null)
            return "";
        return value.getFontName();
    }

    @Override
    public PGCellRenderer getRenderer() {
        return renderer;
    }

    @Override
    public PGCellEditor getEditor() {
        return editor;
    }

    protected class FontEditor extends JComboBox implements PGCellEditor, ActionListener {

        //No need to use an EventListenerList if we only have one listener type
        protected final List listeners = new ArrayList<>();
        protected final Set listenersToRemove = new HashSet<>();

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
            for (Font font : systemFonts)
                this.addItem(font);

            if (value instanceof Font)
                this.setSelectedItem(value);

            this.addActionListener(this);
            return this;
        }

        @Override
        public ListCellRenderer getRenderer() {
            return new FontCellRenderer();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            onSetValue((Font)this.getSelectedItem());
        }

        @Override
        public Object getCellEditorValue() {
            return valueToString(getValue());
        }

        @Override
        public boolean isCellEditable(EventObject anEvent) {
            return !disabled;
        }

        @Override
        public boolean shouldSelectCell(EventObject anEvent) {
            return true;
        }

        @Override
        public boolean stopCellEditing() {
            fireEditingStopped();
            return true;
        }

        @Override
        public void cancelCellEditing() {
            fireEditingCancelled();
        }

        public void fireEditingCancelled() {
            ChangeEvent event = new ChangeEvent(this);

            for (CellEditorListener l : listeners)
                l.editingCanceled(event);

            doClearListeners();
        }

        public void fireEditingStopped() {
            ChangeEvent event = new ChangeEvent(this);

            for (CellEditorListener l : listeners)
                l.editingStopped(event);

            doClearListeners();
        }

        @Override
        public void addCellEditorListener(CellEditorListener l) {
            listeners.add(l);
        }

        @Override
        public void removeCellEditorListener(CellEditorListener l) {
            listenersToRemove.add(l);
        }

        protected void doClearListeners() {
            listeners.removeAll(listenersToRemove);
            listenersToRemove.clear();
        }
    }

    protected class FontRenderer extends JComboBox implements PGCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                       boolean hasFocus, int row, int column) {
            for (Font font : systemFonts)
                this.addItem(font);
            this.setSelectedItem(value);
            setToolTipText(helpString);
            return this;
        }

        @Override
        public ListCellRenderer getRenderer() {
            return new FontCellRenderer();
        }
    }

    protected class FontCellRenderer extends JLabel implements ListCellRenderer {
        @Override
        public Component getListCellRendererComponent(JList list, Font value, int index, boolean isSelected, boolean cellHasFocus) {
            this.setText(value.getFontName());
            this.setFont(value);
            return this;
        }
    }
}