/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013 Geomatys * * This library 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; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotoolkit.gui.swing.parameters.editor; import java.awt.Color; import java.awt.Cursor; import java.awt.GridBagConstraints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import org.geotoolkit.gui.swing.propertyedit.featureeditor.PropertyValueEditor; import org.geotoolkit.font.FontAwesomeIcons; import org.geotoolkit.gui.swing.resource.FontIconJButton; import org.geotoolkit.font.IconBuilder; import org.geotoolkit.gui.swing.resource.MessageBundle; import org.geotoolkit.resources.Errors; import org.geotoolkit.gui.swing.util.SwingUtilities; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.parameter.ParameterValueGroup; import org.openide.util.NbBundle; /** * * @author Quentin Boileau (Geomatys) */ public final class JParameterValueGroupListPanel extends GeneralParameterValuePanel { /** * Expender/Collapse icons. */ private static final ImageIcon CARET_DOWN = IconBuilder.createIcon(FontAwesomeIcons.ICON_CARET_DOWN, 18, Color.BLACK); private static final ImageIcon CARET_RIGHT = IconBuilder.createIcon(FontAwesomeIcons.ICON_CARET_RIGHT, 18, Color.BLACK); /* * JParameterEditor propertyChangeListener transfered to JParameterValueGroupPanel children * GeneralParameterValuePanel. This listener is use by JParameterEditor to know if a parameter * is selected or not in order to update creatorPanel. */ private final PropertyChangeListener editorListener; //JParameterEditor /* * Min/Max group occurences. This define the min/max range for * JParameterValueGroupPanel child list. */ private final int minOccurs; private final int maxOccurs; /* * Custom editor used by JParameterValuePanel */ private final CustomParameterEditor customEditor; /* * List of avaible editors used by JParameterValuePanel */ private final List<PropertyValueEditor> availableEditors; /* * Boolean to know if current ParameterValueGroup is unic. * True if min and max occurs of current ParameterValueGroup descriptor are equals to 1. */ private final boolean isUnicGroup; /* * Expended state */ private boolean isExpended = true; /* * List of JParameterValueGroupPanel child. */ private List<JParameterValueGroupPanel> valueGroupPanels; /** * Keep default label color in order to restore if a * validation error occurs and turn it in red. */ private Color defaultLabelColor; /** * Create JParameterValueGroupPanel from ParameterDescriptorGroup * @param descriptor * @param parent * @param listener */ public JParameterValueGroupListPanel(final ParameterDescriptorGroup descriptor, final JParameterValueGroupPanel parent, final PropertyChangeListener listener, final List<PropertyValueEditor> availableEditors, final CustomParameterEditor customEditor) { this(descriptor.createValue(), parent, listener, availableEditors,customEditor); } /** * Create JParameterValueGroupPanel from ParameterValueGroup * @param valueGroup * @param parent * @param listener */ public JParameterValueGroupListPanel(final ParameterValueGroup valueGroup, final JParameterValueGroupPanel parent, final PropertyChangeListener listener, final List<PropertyValueEditor> availableEditors, final CustomParameterEditor customEditor) { this(Collections.singletonList(valueGroup), valueGroup.getDescriptor(), parent, listener, availableEditors, customEditor); } /** * Create JParameterValueGroupPanel from a list of ParameterValueGroup. * @param valueGroups * @param descriptor * @param parent * @param listener */ JParameterValueGroupListPanel(final List<ParameterValueGroup> valueGroups, final ParameterDescriptorGroup descriptor, final JParameterValueGroupPanel parent, final PropertyChangeListener listener, final List<PropertyValueEditor> availableEditors, final CustomParameterEditor customEditor) { super(descriptor, parent); this.availableEditors = availableEditors; this.customEditor = customEditor; this.editorListener = listener; this.minOccurs = paramDesc.getMinimumOccurs(); this.maxOccurs = paramDesc.getMaximumOccurs(); this.isUnicGroup = (minOccurs==1 && maxOccurs==1); //create groups this.valueGroupPanels = new LinkedList<JParameterValueGroupPanel>(); for (ParameterValueGroup valueGroup : valueGroups) { valueGroupPanels.add(new JParameterValueGroupPanel(valueGroup, this, editorListener, availableEditors, customEditor)); } initComponents(); //expender guiExpenderBtn.setText(null); guiExpenderBtn.setIcon(CARET_DOWN); //ToolTipText on buttons. guiExpenderBtn.setToolTipText(MessageBundle.format("parameters_collapse")); guiNewGroupBtn.setToolTipText(MessageBundle.format("parameters_addNewGroupParameter")); //label guiGroupNameLbl.setText(code); guiGroupNameLbl.setCursor(new Cursor(Cursor.HAND_CURSOR)); guiGroupNameLbl.addMouseListener(this); SwingUtilities.bold(guiGroupNameLbl); defaultLabelColor = guiGroupNameLbl.getForeground(); this.setBorder(new EmptyBorder(1, 1, 1, 1)); if (isUnicGroup) { guiNewGroupBtn.setVisible(false); } updateContent(); } /** * Return all create groups. * @return list of <code>ParameterValueGroup</code> */ public List<ParameterValueGroup> getParameterValues() { final List<ParameterValueGroup> valueGroups = new ArrayList<ParameterValueGroup>(); for (final JParameterValueGroupPanel valueGroup : valueGroupPanels) { valueGroups.add(valueGroup.getParameterValue()); } return valueGroups; } public boolean validateValues() { boolean valid = true; validationError = null; for (JParameterValueGroupPanel groupEditor : valueGroupPanels) { if (!groupEditor.validateValues()) { valid = false; } } final int groupSize = valueGroupPanels.size(); if (groupSize < minOccurs || groupSize > maxOccurs) { //Error final String name = paramDesc.getName().getCode(); final short key; final Object[] param; if (groupSize == 0) { key = Errors.Keys.NoParameter_1; param = new Object[] {name}; } else { key = Errors.Keys.IllegalOccursForParameter_4; param = new Object[] {name, groupSize, minOccurs, maxOccurs}; } validationError = Errors.formatInternational(key, param).toString(); valid = false; } if (!valid && validationError != null) { guiGroupNameLbl.setForeground(Color.RED); } else { guiGroupNameLbl.setForeground(defaultLabelColor); } return valid; } @Override public void setBackgroundColor(final Color color) { topPanel.setBackground(color); if (selected) { this.setBorder(new LineBorder(color, 2)); } else { this.setBorder(new EmptyBorder(1, 1, 1, 1)); } } public int getMinOccurs() { return minOccurs; } public int getMaxOccurs() { return maxOccurs; } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { topPanel = new javax.swing.JPanel(); topLeftPanel = new javax.swing.JPanel(); guiExpenderBtn = new FontIconJButton(FontAwesomeIcons.ICON_CARET_DOWN, 18, Color.BLACK); guiGroupNameLbl = new javax.swing.JLabel(); topRightPanel = new javax.swing.JPanel(); guiNewGroupBtn = new FontIconJButton(FontAwesomeIcons.ICON_PLUS_CIRCLE, 18, Color.BLACK); bottomPanel = new javax.swing.JPanel(); containerPanel = new javax.swing.JPanel(); setLayout(new java.awt.BorderLayout()); topPanel.setLayout(new java.awt.BorderLayout()); topLeftPanel.setAlignmentX(0.0F); topLeftPanel.setOpaque(false); guiExpenderBtn.setBorderPainted(false); guiExpenderBtn.setContentAreaFilled(false); guiExpenderBtn.setFocusable(false); guiExpenderBtn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { guiExpenderBtnActionPerformed(evt); } }); org.openide.awt.Mnemonics.setLocalizedText(guiGroupNameLbl, null); javax.swing.GroupLayout topLeftPanelLayout = new javax.swing.GroupLayout(topLeftPanel); topLeftPanel.setLayout(topLeftPanelLayout); topLeftPanelLayout.setHorizontalGroup( topLeftPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(topLeftPanelLayout.createSequentialGroup() .addComponent(guiExpenderBtn) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(guiGroupNameLbl) .addContainerGap()) ); topLeftPanelLayout.setVerticalGroup( topLeftPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(guiGroupNameLbl, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(guiExpenderBtn, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); topPanel.add(topLeftPanel, java.awt.BorderLayout.LINE_START); topRightPanel.setOpaque(false); guiNewGroupBtn.setBorderPainted(false); guiNewGroupBtn.setContentAreaFilled(false); guiNewGroupBtn.setFocusable(false); guiNewGroupBtn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { guiNewGroupBtnActionPerformed(evt); } }); javax.swing.GroupLayout topRightPanelLayout = new javax.swing.GroupLayout(topRightPanel); topRightPanel.setLayout(topRightPanelLayout); topRightPanelLayout.setHorizontalGroup( topRightPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, topRightPanelLayout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addComponent(guiNewGroupBtn)) ); topRightPanelLayout.setVerticalGroup( topRightPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(guiNewGroupBtn, javax.swing.GroupLayout.DEFAULT_SIZE, 15, Short.MAX_VALUE) ); topPanel.add(topRightPanel, java.awt.BorderLayout.LINE_END); add(topPanel, java.awt.BorderLayout.PAGE_START); bottomPanel.setLayout(new java.awt.BorderLayout()); containerPanel.setLayout(new java.awt.GridBagLayout()); bottomPanel.add(containerPanel, java.awt.BorderLayout.PAGE_START); add(bottomPanel, java.awt.BorderLayout.CENTER); }// </editor-fold>//GEN-END:initComponents /** * Expend/Collapse children parameters. * @param evt */ private void guiExpenderBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_guiExpenderBtnActionPerformed isExpended = !isExpended; if (isExpended) { guiExpenderBtn.setIcon(CARET_DOWN); guiExpenderBtn.setToolTipText(MessageBundle.format("parameters_collapse")); bottomPanel.setVisible(true); } else { guiExpenderBtn.setIcon(CARET_RIGHT); guiExpenderBtn.setToolTipText(MessageBundle.format("parameters_expend")); bottomPanel.setVisible(false); } }//GEN-LAST:event_guiExpenderBtnActionPerformed /** * Add new JParameterValueGroupPanel to children. * @param evt */ private void guiNewGroupBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_guiNewGroupBtnActionPerformed //create new group only if current number of groups is < to max occurences defined by group descriptor. if (valueGroupPanels.size() < maxOccurs) { final ParameterValueGroup newGroup = ((ParameterDescriptorGroup)paramDesc).createValue(); valueGroupPanels.add(new JParameterValueGroupPanel(newGroup, this, editorListener, availableEditors, customEditor)); updateContent(); } }//GEN-LAST:event_guiNewGroupBtnActionPerformed private void guiRemoveGroupBtnAction(ActionEvent event, int index) { //remove a group only if current number of groups is > to min occurences defined by group descriptor. if (valueGroupPanels.size() > minOccurs) { valueGroupPanels.remove(index); updateContent(); } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel bottomPanel; private javax.swing.JPanel containerPanel; private javax.swing.JButton guiExpenderBtn; private javax.swing.JLabel guiGroupNameLbl; private javax.swing.JButton guiNewGroupBtn; private javax.swing.JPanel topLeftPanel; private javax.swing.JPanel topPanel; private javax.swing.JPanel topRightPanel; // End of variables declaration//GEN-END:variables /** * Remove and rebuild parameters list using GridBag layout. */ @Override public void updateContent() { guiGroupNameLbl.setText(code); if (valueGroupPanels.size() >= maxOccurs) { guiNewGroupBtn.setEnabled(false); } else { guiNewGroupBtn.setEnabled(true); } boolean canRemove = (valueGroupPanels.size() > minOccurs); //clear containerPanel.removeAll(); GridBagConstraints constraint; JLabel guiNumberLbl; JButton guiRemoveGroupBtn; int index = 0; //first all simple parameters for (JParameterValueGroupPanel group : valueGroupPanels) { final Color color = index % 2 == 0 ? UIManager.getColor("Label.background") : SwingUtilities.darker(UIManager.getColor("Label.background"), 0.85f); if (group != null) { if (!isUnicGroup) { ////////////////// // group number constraint = new GridBagConstraints(); constraint.gridx = 0; constraint.gridy = index; constraint.weightx = 0.0; constraint.weighty = 0.0; constraint.fill = GridBagConstraints.BOTH; guiNumberLbl = new JLabel(String.valueOf(index+1)); //start at 1 guiNumberLbl.setBorder(new EmptyBorder(0, 10, 0, 10)); guiNumberLbl.setOpaque(true); guiNumberLbl.setBackground(color); containerPanel.add(guiNumberLbl, constraint); } /////////////////// //group panel constraint = new GridBagConstraints(); constraint.gridx = 1; constraint.gridy = index; constraint.weightx = 1.0; constraint.weighty = 0.0; constraint.fill = GridBagConstraints.BOTH; if (isUnicGroup) constraint.gridwidth = GridBagConstraints.REMAINDER; group.setBorder(new LineBorder(color, 2)); group.setOpaque(false); group.setBackground(color); containerPanel.add(group, constraint); //if current Group is root group or if had multiplicity 1 - 1 if (!isUnicGroup) { /////////////////// //group remove button constraint = new GridBagConstraints(); constraint.gridx = 2; constraint.gridy = index; constraint.weightx = 0.0; constraint.weighty = 0.0; constraint.fill = GridBagConstraints.BOTH; final int currentIndex = index; guiRemoveGroupBtn = new FontIconJButton(FontAwesomeIcons.ICON_MINUS, 18, Color.RED); guiRemoveGroupBtn.setBorder(new EmptyBorder(0, 10, 0, 10)); guiRemoveGroupBtn.setOpaque(true); guiRemoveGroupBtn.setBackground(color); guiRemoveGroupBtn.setEnabled(canRemove); guiRemoveGroupBtn.setToolTipText(MessageBundle.format("parameters_removeGroup")); guiRemoveGroupBtn.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { guiRemoveGroupBtnAction(e, currentIndex); } }); containerPanel.add(guiRemoveGroupBtn, constraint); } index++; } } this.revalidate(); } @Override public void propertyChange(PropertyChangeEvent evt) { } }