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

org.nuiton.math.matrix.viewer.MatrixViewerPanel Maven / Gradle / Ivy

The newest version!
/*
 * #%L
 * Nuiton Matrix :: GUI
 * %%
 * Copyright (C) 2010 - 2012 Codelutin, Chatellier Eric
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * This program 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 General Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

package org.nuiton.math.matrix.viewer;

import static org.nuiton.i18n.I18n.t;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToggleButton.ToggleButtonModel;

import org.nuiton.math.matrix.MatrixND;
import org.nuiton.util.Resource;

/**
 * Panel that can display matrix list details (dimension) and rendering solutions.
 * 
 * @author chatellier
 * @version $Revision$
 * 
 * Last update : $Date$
 * By : $Author$
 */
public class MatrixViewerPanel extends JPanel {

    /** serialVersionUID. */
    private static final long serialVersionUID = -5447856858278176837L;

    public static final String PROPERTY_MATRIX_RENDERER_SOLUTION = "matrixRendererSolution";

    public static final String PROPERTY_MATRIX_RENDERERS = "matrixRenderers";

    public static final String PROPERTY_MATRIX = "matrix";

    /** Matrix renderer list solution. (default to {@link MatrixRendererSolution#RADIO_BUTTON} */
    protected MatrixRendererSolution matrixRendererSolution = MatrixRendererSolution.RADIO_BUTTON;

    /** Matrix renderer plugins. */
    protected Map matrixRenderers;

    /** La matrice courrement affichées. */
    protected MatrixND matrix;

    protected MatrixDimensionPanel dimensionPanel;

    protected RadioButtonRenderingPanel radioPanel;

    protected IconButtonRenderingPanel iconPanel;

    protected JPanel renderingComponentContainer;

    /**
     * Map entre les renderers et les composants (valorisé par bouton de
     * rendu) et utilisé par le choix du renderer.
     */
    protected Map componentForRenderers;

    public MatrixViewerPanel() {
        // keep order
        matrixRenderers = new LinkedHashMap<>();
        componentForRenderers = new HashMap<>();

        buildPanel();
    }

    public MatrixRendererSolution getMatrixRendererSolution() {
        return matrixRendererSolution;
    }

    public void setMatrixRendererSolution(MatrixRendererSolution matrixRendererSolution) {
        MatrixRendererSolution oldValue = this.matrixRendererSolution;
        this.matrixRendererSolution = matrixRendererSolution;
        firePropertyChange(PROPERTY_MATRIX_RENDERER_SOLUTION, oldValue, matrixRendererSolution);
    }

    public void addMatrixRenderer(MatrixRenderer matrixRenderer) {
        addMatrixRenderer(matrixRenderer, false);
    }

    /**
     * Add new matrix renderer.
     * 
     * @param matrixRenderer matrix renderer
     * @param defautRenderer renderer can be called with a null matrix to get default rendering
     */
    public void addMatrixRenderer(MatrixRenderer matrixRenderer, boolean defautRenderer) {
        matrixRenderers.put(matrixRenderer, defautRenderer);
        firePropertyChange(PROPERTY_MATRIX_RENDERERS, null, matrixRenderers);
    }

    public void removeMatrixRenderer(Object matrixRenderer) {
        matrixRenderers.remove(matrixRenderer);
        firePropertyChange(PROPERTY_MATRIX_RENDERERS, null, matrixRenderers);
    }

    /**
     * Set currently displayed matrix.
     * 
     * @param matrix new matrix to display
     */
    public void setMatrix(MatrixND matrix) {
        MatrixND oldValue = this.matrix;
        this.matrix = matrix;
        firePropertyChange(PROPERTY_MATRIX, oldValue, matrix);
    }

    /**
     * Get currently displayed matrix.
     * 
     * @return current matrix
     */
    public MatrixND getMatrix() {
        return matrix;
    }

    /**
     * Add new action.
     * 
     * @param matrixDimentionAction new action
     */
    public void addMatrixDimentionAction(MatrixDimensionAction matrixDimentionAction) {
        dimensionPanel.addMatrixDimentionAction(matrixDimentionAction);
    }

    /** Matrix list combo renderer. */
    protected static class MatrixComboRenderer extends DefaultListCellRenderer {

        /** serialVersionUID. */
        private static final long serialVersionUID = 6151127818315270895L;

        @Override
        public Component getListCellRendererComponent(JList list, Object value,
                int index, boolean isSelected, boolean cellHasFocus) {

            String matrixName = null;
            if (value != null) {
                matrixName = t((String)value);
            }
            return super.getListCellRendererComponent(list, matrixName, index, isSelected, cellHasFocus);
        }
    }

    /** Button model from button containing rendered instance. */
    protected static class RendererButtonModel extends ToggleButtonModel {

        /** serialVersionUID. */
        private static final long serialVersionUID = -5737246124430280412L;

        protected MatrixRenderer renderer;
        
        public RendererButtonModel(MatrixRenderer renderer) {
            this.renderer = renderer;
        }
        
        public MatrixRenderer getRenderer() {
            return renderer;
        }
    }

    /**
     * Icon button rendering panel.
     * Also contains main render action button (arrow).
     */
    protected class IconButtonRenderingPanel extends JPanel implements PropertyChangeListener, ActionListener {

        /** serialVersionUID. */
        private static final long serialVersionUID = 2591696695747738619L;

        protected ButtonGroup buttonGroup;

        public IconButtonRenderingPanel() {
            super(new GridBagLayout());
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            rebuildPanel();
            validate();
            repaint();
        }

        /**
         * Rebuild radio button lists.
         */
        protected void rebuildPanel() {
            removeAll();

            JButton renderButton = new JButton(Resource.getIcon("/icons/fatcow/report_go.png"));
            renderButton.setActionCommand("render");
            renderButton.addActionListener(this);
            add(renderButton, new GridBagConstraints(0, 0, 1, 1, 1, 1,
                    GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));

            if (matrixRendererSolution == MatrixRendererSolution.ICON) {

                int index = 1;
                buttonGroup = new ButtonGroup();
                for (MatrixRenderer renderer : matrixRenderers.keySet()) {
                    JToggleButton radioButton = new JToggleButton(renderer.getIcon());
                    radioButton.addActionListener(this);
                    radioButton.setModel(new RendererButtonModel(renderer));

                    // auto select first matrix renderer
                    if (index == 1) {
                        radioButton.setSelected(true);
                    }

                    buttonGroup.add(radioButton);
                    add(radioButton, new GridBagConstraints(0, index, 1, 1, 1, 0,
                            GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
                    index++;
                }
            }
        }

        public MatrixRenderer getSelectedRender() {
            MatrixRenderer renderer = null;
            RendererButtonModel model = (RendererButtonModel)buttonGroup.getSelection();
            if (model != null) {
                renderer = model.getRenderer();
            }
            return renderer;
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            String actionCommand = e.getActionCommand();

            if ("render".equals(actionCommand)) {
                performRendering();
            } else {
                // clic on render button
                updateSelectedRenderingComponent();
            }
        }

        protected void performRendering() {
            // get matrix to display filtered
            MatrixND matrix = dimensionPanel.getModifiedMatrix();

            // matrice superieur a 2 dimensions non geree!!
            if (matrix.getDimCount() > 2) {
                JOptionPane.showMessageDialog(this, t("nuitonmatrix.viewer.matrix.more.2d"),
                        t("nuitonmatrix.error"), JOptionPane.ERROR_MESSAGE);
            } else {

                // get all display component for each renderer
                componentForRenderers.clear();
                for (MatrixRenderer matrixRenderer : matrixRenderers.keySet()) {
                    Component component = matrixRenderer.getComponent(matrix);
                    componentForRenderers.put(matrixRenderer, component);
                }

                // update UI with selected component
                updateSelectedRenderingComponent();

                // auto select the one with non default description (to see data matrix)
                MatrixRenderer selectedRender = radioPanel.getSelectedRender();
                if (matrixRenderers.get(selectedRender)) { // si c'est deja un composant non default, on le laisse
                    for (Map.Entry matrixRendererDefaults : matrixRenderers.entrySet()) {
                        if (!matrixRendererDefaults.getValue()) {
                            radioPanel.setSelectedRender(matrixRendererDefaults.getKey());
                            break;
                        }
                    }
                }
            }
        }
    }

    /** Radio button rendering panel. */
    protected class RadioButtonRenderingPanel extends JPanel implements PropertyChangeListener, ItemListener {

        /** serialVersionUID. */
        private static final long serialVersionUID = -6312518069621077533L;

        protected ButtonGroup buttonGroup;

        public RadioButtonRenderingPanel() {
            super(new GridBagLayout());
        }

        @Override
        public void propertyChange(PropertyChangeEvent evt) {
            rebuildPanel();
            validate();
            repaint();
        }

        /**
         * Rebuild radio button lists.
         */
        protected void rebuildPanel() {
            removeAll();
            if (matrixRendererSolution == MatrixRendererSolution.RADIO_BUTTON) {

                int index = 0;
                buttonGroup = new ButtonGroup();
                for (MatrixRenderer renderer : matrixRenderers.keySet()) {
                    JRadioButton radioButton = new JRadioButton(renderer.getName());
                    radioButton.addItemListener(this);
                    radioButton.setModel(new RendererButtonModel(renderer));
                    buttonGroup.add(radioButton);
                    
                    // auto select first matrix renderer
                    if (index == 0) {
                        radioButton.setSelected(true);
                    }

                    add(radioButton, new GridBagConstraints(index, 0, 1, 1, 1, 1,
                            GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
                    index++;
                }

                setVisible(true);
            }
            else {
                setVisible(false);
            }
        }

        public MatrixRenderer getSelectedRender() {
            MatrixRenderer renderer = null;
            RendererButtonModel model = (RendererButtonModel)buttonGroup.getSelection();
            if (model != null) {
                renderer = model.getRenderer();
            }
            return renderer;
        }

        /**
         * Selectionne le radio button associé au renderer specifié.
         */
        public void setSelectedRender(MatrixRenderer renderer) {
            Enumeration elements = buttonGroup.getElements();
            while (elements.hasMoreElements()) {
                AbstractButton abstractButton = elements.nextElement();
                RendererButtonModel buttonModel = (RendererButtonModel)abstractButton.getModel();
                if (buttonModel.getRenderer().equals(renderer)) {
                    buttonGroup.setSelected(buttonModel, true);
                }
            }
        }

        @Override
        public void itemStateChanged(ItemEvent itemEvent) {
            if (itemEvent.getStateChange() == ItemEvent.SELECTED) {
                updateSelectedRenderingComponent();
            }
        }
    }

    /**
     * Build main panel.
     */
    protected void buildPanel() {

        setLayout(new BorderLayout());

        // split main ui left/rigth
        JPanel editionSidePanel = new JPanel(new BorderLayout());
        JPanel renderSidePanel = new JPanel(new BorderLayout());
        JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, editionSidePanel, renderSidePanel);
        mainSplitPane.setDividerLocation(0.3);
        add(mainSplitPane, BorderLayout.CENTER);

        // panel d'affichage des dimensions
        dimensionPanel = new MatrixDimensionPanel();
        editionSidePanel.add(dimensionPanel, BorderLayout.CENTER);
        addPropertyChangeListener(PROPERTY_MATRIX, dimensionPanel);

        // fleche de d'action de rendu
        // render type : icon
        iconPanel = new IconButtonRenderingPanel();
        editionSidePanel.add(iconPanel, BorderLayout.EAST);
        addPropertyChangeListener(PROPERTY_MATRIX_RENDERER_SOLUTION, iconPanel);
        addPropertyChangeListener(PROPERTY_MATRIX_RENDERERS, iconPanel);

        // render type : combo box

        // current rendering pane
        renderingComponentContainer = new JPanel(new BorderLayout());
        renderSidePanel.add(renderingComponentContainer, BorderLayout.CENTER);

        // render type : radio button
        radioPanel = new RadioButtonRenderingPanel();
        renderSidePanel.add(radioPanel, BorderLayout.SOUTH);
        addPropertyChangeListener(PROPERTY_MATRIX_RENDERER_SOLUTION, radioPanel);
        addPropertyChangeListener(PROPERTY_MATRIX_RENDERERS, radioPanel);
    }

    /**
     * Set rendering component in rendering container.
     */
    public void updateSelectedRenderingComponent() {
        renderingComponentContainer.removeAll();
        
        MatrixRenderer matrixRenderer = null;
        switch (matrixRendererSolution) {
        case ICON:
            matrixRenderer = iconPanel.getSelectedRender();
            break;
        case RADIO_BUTTON:
            matrixRenderer = radioPanel.getSelectedRender();
            break;
        }

        if (!componentForRenderers.isEmpty()) {
            if (matrixRenderer != null) {
                Component component = componentForRenderers.get(matrixRenderer);
                if (component != null) {
                    renderingComponentContainer.add(component, BorderLayout.CENTER);
                }
            }
        } else {
            // if enables default rendering
            if (matrixRenderers.get(matrixRenderer)) {
                Component component = matrixRenderer.getComponent(null);
                if (component != null) {
                    renderingComponentContainer.add(component, BorderLayout.CENTER);
                }
            }
        }

        renderingComponentContainer.validate();
        renderingComponentContainer.repaint();
    }

    /**
     * Init renderering by autoselecting some dimensions values and some dimensions
     * action. And perform rendering.
     * 
     * @param dimSelectedValues selected values in each dimensions
     * @param selectedActions selected action in each dimensions
     * @throws IllegalArgumentException if matrix has not been set
     */
    public void initRenderering(List[] dimSelectedValues, int[] selectedActions) {
        if (this.matrix == null) {
            throw new IllegalArgumentException("Must set matrix first");
        }
        dimensionPanel.initRenderering(dimSelectedValues, selectedActions);
        iconPanel.performRendering();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy