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

com.dua3.meja.ui.swing.CellEditorPane Maven / Gradle / Ivy

/*
 * Copyright 2015 Axel Howind ([email protected]).
 *
 * 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.
 */
package com.dua3.meja.ui.swing;

import com.dua3.meja.model.Cell;
import com.dua3.meja.model.CellStyle;
import com.dua3.meja.model.CellType;
import com.dua3.meja.model.HAlign;
import com.dua3.meja.model.VAlign;
import com.dua3.utility.data.Color;
import com.dua3.utility.math.geometry.Scale2f;
import com.dua3.utility.swing.StyledDocumentConverter;
import com.dua3.utility.swing.SwingUtil;
import com.dua3.utility.text.Font;
import com.dua3.utility.text.RichText;

import javax.swing.JTextPane;
import javax.swing.text.AbstractDocument;
import javax.swing.text.BoxView;
import javax.swing.text.ComponentView;
import javax.swing.text.Element;
import javax.swing.text.IconView;
import javax.swing.text.LabelView;
import javax.swing.text.ParagraphView;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledEditorKit;
import javax.swing.text.View;
import javax.swing.text.ViewFactory;
import java.util.Arrays;

/**
 * @author Axel Howind ([email protected])
 */
@SuppressWarnings("serial")
public class CellEditorPane extends JTextPane {

    /**
     * A subclass of BoxView that enables alignment options.
     */
    final class AlignedBoxView extends BoxView {

        AlignedBoxView(Element elem, int axis) {
            super(elem, axis);
        }

        @Override
        protected void layoutMajorAxis(int targetSpan, int axis, int[] offsets, int[] spans) {

            super.layoutMajorAxis(targetSpan, axis, offsets, spans);

            int textBlockHeight = Arrays.stream(spans).sum();

            final int available = targetSpan - textBlockHeight;
            float offset;
            float increase;
            switch (vAlign) {
                case ALIGN_TOP -> {
                    offset = 0;
                    increase = 0;
                }
                case ALIGN_BOTTOM, ALIGN_DISTRIBUTED -> {
                    offset = available;
                    increase = 0;
                }
                case ALIGN_MIDDLE -> {
                    offset = (float) available / 2;
                    increase = 0;
                }
                case ALIGN_JUSTIFY -> {
                    offset = (float) available / spans.length;
                    increase = offset;
                }
                default -> throw new IllegalStateException("unexpected value: " + vAlign);
            }

            for (int i = 0; i < offsets.length; i++) {
                offsets[i] += Math.round(offset + i * increase);
            }

        }
    }

    /**
     * A custom EditorKit to allow vertical aligned text.
     */
    final class CellEditorKit extends StyledEditorKit {
        @Override
        public ViewFactory getViewFactory() {
            return new CellEditorViewFactory();
        }
    }

    /**
     * A ViewFactory for the custom EditorKit.
     */
    final class CellEditorViewFactory implements ViewFactory {

        @Override
        public View create(Element elem) {
            String kind = elem.getName();
            if (kind == null) {
                return new LabelView(elem);
            }

            return switch (kind) {
                case AbstractDocument.ContentElementName -> new LabelView(elem);
                case AbstractDocument.ParagraphElementName -> new ParagraphView(elem);
                case AbstractDocument.SectionElementName -> new AlignedBoxView(elem, View.Y_AXIS);
                case StyleConstants.ComponentElementName -> new ComponentView(elem);
                case StyleConstants.IconElementName -> new IconView(elem);
                default -> new LabelView(elem);
            };
        }

    }

    /**
     * Translate {@code HAlign.ALIGN_AUTOMATIC} to the actual value for the cell
     * type.
     *
     * @param hAlign the horizontal alignment
     * @param type   the cell type
     * @return 
    *
  • {@code hAlign}, if {@code hAlign!=HAlign.ALIGN_AUTOMATIC}
  • *
  • otherwise the horizontal alignment to apply to cells of the given * type
  • *
*/ public static HAlign getHAlign(HAlign hAlign, CellType type) { if (hAlign != HAlign.ALIGN_AUTOMATIC) { return hAlign; } return switch (type) { case BLANK, BOOLEAN, ERROR, NUMERIC, DATE, DATE_TIME -> HAlign.ALIGN_RIGHT; case TEXT, FORMULA -> HAlign.ALIGN_LEFT; }; } private VAlign vAlign = VAlign.ALIGN_TOP; /** * Construct a new CellEditorPane. */ public CellEditorPane() { setEditorKit(new CellEditorKit()); } /** * Get a {@link SimpleAttributeSet} corresponding to the cellstyle. * * @param cellStyle the cell style * @param cell the cell (because cell tye influences the style attributes) * @return a SimpleAttributeSet */ public SimpleAttributeSet getCellAttributes(final CellStyle cellStyle, Cell cell) { SimpleAttributeSet dfltAttr = new SimpleAttributeSet(); HAlign hAlign = getHAlign(cellStyle.getHAlign(), cell.getResultType()); switch (hAlign) { case ALIGN_LEFT -> StyleConstants.setAlignment(dfltAttr, StyleConstants.ALIGN_LEFT); case ALIGN_CENTER -> StyleConstants.setAlignment(dfltAttr, StyleConstants.ALIGN_CENTER); case ALIGN_RIGHT -> StyleConstants.setAlignment(dfltAttr, StyleConstants.ALIGN_RIGHT); case ALIGN_JUSTIFY -> StyleConstants.setAlignment(dfltAttr, StyleConstants.ALIGN_JUSTIFIED); // ALIGN_AUTOMATIC should already be resolved default -> throw new IllegalStateException("unexpected value: " + hAlign); } return dfltAttr; } /** * Set the editor content to the content of the given cell. * * @param cell the cell to display * @param scale the font scaling factor to use * @param eval set to true to display formula results instead of the formula * itself */ public void setContent(Cell cell, Scale2f scale, boolean eval) { CellStyle cellStyle = cell.getCellStyle(); Color fg = cellStyle.getFillFgColor(); Color bg = cellStyle.getFillBgColor(); Font font = cellStyle.getFont(); setBackground(SwingUtil.toAwtColor(fg)); setForeground(SwingUtil.toAwtColor(bg)); final RichText text; if (!eval && cell.getCellType() == CellType.FORMULA) { text = RichText.valueOf("=" + cell.getFormula()); } else { text = cell.getAsText(getLocale()); } setDocument( StyledDocumentConverter.create( StyledDocumentConverter.addStyledAttributes(getCellAttributes(cellStyle, cell)), StyledDocumentConverter.scale(scale.sy()), StyledDocumentConverter.defaultFont(font) ).convert(text) ); this.vAlign = cellStyle.getVAlign(); revalidate(); repaint(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy