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

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

The newest version!
/*
 * #%L
 * Nuiton Matrix :: GUI
 * %%
 * Copyright (C) 2010 - 2020 Codelutin
 * %%
 * 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.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

import javax.swing.AbstractButton;
import javax.swing.ButtonGroup;
import javax.swing.ButtonModel;
import javax.swing.DefaultListModel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JToggleButton.ToggleButtonModel;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuiton.math.matrix.MatrixND;

/**
 * Panel d'affichage des dimensions.
 * 
 * @author chatellier
 * @version $Revision$
 * 
 * Last update : $Date$
 * By : $Author$
 */
public class MatrixDimensionPanel extends JPanel implements PropertyChangeListener {

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

    /** Class logger. */
    private static Log log = LogFactory.getLog(MatrixDimensionPanel.class);

    /** Matrix to display (original). */
    protected MatrixND matrix;

    protected List subPanelList;

    protected List matrixDimensionActions;

    public MatrixDimensionPanel() {
        setLayout(new GridLayout(0, 1));
        subPanelList = new ArrayList<>();
        matrixDimensionActions = new ArrayList<>();

        // default sum all action
        matrixDimensionActions.add(new SumAllAction());
    }

    /**
     * Add new action. Protected to force call on MatrixViewerPanel.
     * 
     * @param matrixDimentionAction new action
     */
    protected void addMatrixDimentionAction(MatrixDimensionAction matrixDimentionAction) {
        matrixDimensionActions.add(matrixDimentionAction);
    }

    @Override
    public void propertyChange(PropertyChangeEvent evt) {
        this.matrix = (MatrixND)evt.getNewValue();
        buildDimensionPanel();
        validate();
        repaint();
    }
    
    public MatrixND getModifiedMatrix() {
        MatrixND reducedMatrix = createAndReduce(matrix);
        return reducedMatrix;
    }

    /** Button model from button containing action instance */
    protected static class MatrixActionButtonModel extends ToggleButtonModel {

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

        protected MatrixDimensionAction matrixAction;
        
        public MatrixActionButtonModel(MatrixDimensionAction matrixAction) {
            this.matrixAction = matrixAction;
        }
        
        public MatrixDimensionAction getMatrixAction() {
            return matrixAction;
        }
    }

    protected class SubDimensionPanel extends JPanel {

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

        protected int index;

        protected String semanticName;

        protected List semantic;

        /**
         * Declaration d'un button group avec possibilité de deselectionne
         * tous les boutons (methode setSelected surchargée).
         */
        protected ButtonGroup buttonGroup = new ButtonGroup() {
            /** serialVersionUID. */
            private static final long serialVersionUID = 8214289174634749701L;

            @Override
            public void setSelected(ButtonModel m, boolean b) {
                if (b) {
                    super.setSelected(m, b);
                }
                else {
                    clearSelection();
                }
            }
        };
        
        /*
         * Gere a la main le group de bouton, car sinon, lors que le premier
         * bouton est sélectionné, on ne peut pas le deselection
        protected List buttonList = new ArrayList();*/

        protected JList semList;

        public SubDimensionPanel(int index, String semanticName, List semantic) {
            super(new GridBagLayout());
            this.index = index;
            this.semanticName = semanticName;
            this.semantic = semantic;
            renderSubPanel();
        }

        protected void renderSubPanel() {
            // semantic name
            JLabel semName = new JLabel(semanticName);
            add(semName, new GridBagConstraints(0, 0, 1, 1, 1, 0, GridBagConstraints.CENTER,
                    GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));

            int nbActionAdded = 0;
            for (MatrixDimensionAction matrixDimensionAction : matrixDimensionActions) {

                boolean addSumAll = matrixDimensionAction.canApply(index, semantic);

                if (addSumAll) {
                    // sum all button
                    JToggleButton sumAll = new JToggleButton(matrixDimensionAction.getIcon());
                    sumAll.setSelectedIcon(matrixDimensionAction.getSelectedIcon());
                    sumAll.setModel(new MatrixActionButtonModel(matrixDimensionAction));
                    sumAll.setToolTipText(matrixDimensionAction.getDescription());
                    add(sumAll, new GridBagConstraints(1 + nbActionAdded, 0, 1, 1, 0, 0, GridBagConstraints.WEST,
                            GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
                    buttonGroup.add(sumAll);
                    nbActionAdded++;
                }
            }

            // semantic list
            //MatrixDimensionFilter filter = matrixDimensionFilters.get(index);
            semList = new JList();
            List dimSemantic = semantic;
            /*if (filter != null) {
                dimSemantic = filter.filterSemantic(dimSemantic);
            }*/
            SemanticListModel semModel = new SemanticListModel(dimSemantic);
            semList.setModel(semModel);
            /*if (filter != null) {
                ListCellRenderer renderer = filter.getListCellRenderer();
                if (renderer != null) {
                    semList.setCellRenderer(renderer);
                }
            }*/
            add(new JScrollPane(semList), new GridBagConstraints(0, 1, 1 + nbActionAdded, 1, 1, 1,
                    GridBagConstraints.WEST, GridBagConstraints.BOTH, new Insets(0, 0, 5, 0), 0, 0));
        }

        public JList getList() {
            return semList;
        }

        /**
         * Return true if user has selected this action.
         */
        public boolean isSelected() {
            boolean result = false;
            MatrixActionButtonModel buttonModel = (MatrixActionButtonModel)buttonGroup.getSelection();
            if (buttonModel != null) {
                result = true;
            }
            return result;
        }

        /**
         * Apply the selected action.
         */
        public MatrixND apply(MatrixND matrix, int dim) {
            MatrixActionButtonModel buttonModel = (MatrixActionButtonModel)buttonGroup.getSelection();
            MatrixDimensionAction matrixAction = buttonModel.getMatrixAction();
            matrix = matrixAction.apply(matrix, dim);
            return matrix;
        }
    }

    /**
     * Build dimension panel.
     */
    protected void buildDimensionPanel() {
        subPanelList.clear();
        removeAll();
        
        if (matrix != null) {
            int index = 0;
            for (List semantic : matrix.getSemantics()) {

                // compute dimension name
                String dimensionName = t(matrix.getDimensionName(index));
                if (dimensionName == null || dimensionName.isEmpty()) {
                    dimensionName = t("nuitonmatrix.viewer.dimnameindex", index);
                }

                SubDimensionPanel dimPanel = new SubDimensionPanel(index, dimensionName, semantic);
                add(dimPanel);
                subPanelList.add(dimPanel);
                index++;
            }
        }
    }
    
    public static class SemanticListModel extends DefaultListModel {

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

        protected List semantic;

        public SemanticListModel(List semantic) {
            this.semantic = semantic;
        }

        @Override
        public int getSize() {
            return semantic.size();
        }

        @Override
        public Object getElementAt(int index) {
            return semantic.get(index);
        }
    }

    /**
     * Reduit, somme et filtre la matrice sur les dimensions selectionnés,
     * les boutons d'action selections et les filtres enregistrés.
     * 
     * @param matrix initial matrix to reduce
     * @return filtred, reduced and sommed matrix
     */
    protected MatrixND createAndReduce(MatrixND matrix) {

        if (log.isDebugEnabled()) {
            log.debug("Matrice before submatrix : " + matrix);
        }

        // la matrice doit être reduite avant tout et en une seule
        // fois pour fonctionner avec des matrices réelles ou des proxy
        int[][] dimIndices = new int[subPanelList.size()][];
        for (int i = 0; i < subPanelList.size(); i++) {
            SubDimensionPanel subDimPanel = subPanelList.get(i);
            JList list = subDimPanel.getList();
            int [] indList = list.getSelectedIndices();

            if (indList.length == 0) {
                // si rien n'est selectionné on selectionne tout
                list.setSelectionInterval(0, list.getModel().getSize()-1);
                indList = list.getSelectedIndices();
            }

            if (0 < indList.length && indList.length < matrix.getDim(i)) {
                dimIndices[i] = indList;
            }
        }

        // reduction effective de la matrice
        matrix = matrix.getSubMatrix(dimIndices);

        if (log.isDebugEnabled()) {
            log.debug("Matrix after submatrix : " + matrix);
        }

        // Effectue la somme si l'utilisateur a selectionné l'option somme
        // dans le panel
        for (int d = 0; d < subPanelList.size(); d++) {
            SubDimensionPanel subDimPanel = subPanelList.get(d);

            // il se peux que le nom soit déjà suffixé d'une précédente filtration
            String dimName = matrix.getDimensionName(d);
            dimName = StringUtils.removeEnd(dimName, "*");
            matrix.setDimensionName(d, dimName);

            if (subDimPanel.isSelected()) {
                // on ajoute une * au nom de la dimension
                // l'action devrait normalement surcharger ce nom
                matrix.setDimensionName(d, dimName + "*");
                // on applique l'operation
                matrix = subDimPanel.apply(matrix, d);
            }

            if (log.isDebugEnabled()) {
                log.debug("Matrix after sum on dim " + d + ": " + matrix);
            }
        }

        if (log.isDebugEnabled()) {
            log.debug("Matrix bebore reduce: " + matrix);
        }

        // arrive ici on a une matrice qui a des tailles de dimension 1
        // et un tableau des legende pour chaque dimension

        // il faut que la matrice est 2 dimensions
        // reduction de la matrice
        MatrixND result = matrix.reduce(2);

        return result;
    }

    /**
     * Autoselect some dimensions values and some dimensions
     * action. And perform rendering.
     * 
     * @param dimSelectedValues selected values in each dimensions
     * @param selectedActions selected actions in each dimensions
     */
    public void initRenderering(List[] dimSelectedValues,
            int[] selectedActions) {
        
        // values selection
        for (int dimIndex = 0; dimIndex < dimSelectedValues.length; dimIndex++) {
            List selectedValues = dimSelectedValues[dimIndex];
            if (selectedValues != null) {
                SubDimensionPanel panel = subPanelList.get(dimIndex);
                panel.semList.clearSelection();
                for (Object value : selectedValues) {
                    int index = panel.semantic.indexOf(value);
                    panel.semList.addSelectionInterval(index, index);
                }
            }
        }
        
        // action selection
        for (int dimIndex = 0; dimIndex < selectedActions.length; dimIndex++) {
            int actionIndices = selectedActions[dimIndex];
            SubDimensionPanel panel = subPanelList.get(dimIndex);
            int buttonIndex = 0;
            Enumeration buttons = panel.buttonGroup.getElements();
            while (buttons.hasMoreElements()) {
                AbstractButton button = buttons.nextElement();
                if (actionIndices == buttonIndex) {
                    button.setSelected(true);
                }
                buttonIndex++;
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy