/* * 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.creator; import java.awt.Color; import java.awt.Cursor; import java.awt.GridBagConstraints; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.LinkedList; import java.util.List; import javax.swing.ImageIcon; import javax.swing.border.EmptyBorder; import org.apache.sis.parameter.ParameterBuilder; import org.apache.sis.util.iso.SimpleInternationalString; 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.utility.parameter.ParametersExt; import org.geotoolkit.gui.swing.util.SwingUtilities; import org.opengis.parameter.GeneralParameterDescriptor; import org.opengis.parameter.ParameterDescriptor; import org.opengis.parameter.ParameterDescriptorGroup; import org.opengis.util.InternationalString; /** * * @author Quentin Boileau (Geomatys) */ public final class JParameterDescriptorGroupPanel extends GeneralParameterDescriptorPanel { /** * 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); /** * Prefix used on new parameter or group creation. */ private static final String GROUP_PREFIX = "group"; private static final String PARAM_PREFIX = "param"; /** * JParameterEditor propertyChangeListener transfered to JParameterDescriptorGroupPanel children * GeneralParameterDescriptorPanel. This listener is use by JParameterEditor to know if a parameter * is selected or not in order to update creatorPanel. */ private final PropertyChangeListener focusListener; //JParameterEditor private boolean rootGroup = false; private boolean editable; private boolean removable; private boolean expended = true; private int minOccurs; private int maxOccurs; private List<GeneralParameterDescriptorPanel> simpleParameters; private List<GeneralParameterDescriptorPanel> groupParameters; /** * Create new form JParametersCreator */ public JParameterDescriptorGroupPanel(final ParameterDescriptorGroup descGroup, final EditableParameterFilter filter, final JParameterDescriptorGroupPanel parent, final PropertyChangeListener listener) { super(descGroup, parent); this.focusListener = listener; this.rootGroup = parent == null; this.editable = filter != null ? filter.isEditable(descGroup) : true; this.removable = filter != null ? filter.isRemovable(descGroup) : true; this.minOccurs = descGroup.getMinimumOccurs(); this.maxOccurs = descGroup.getMaximumOccurs(); this.simpleParameters = new LinkedList<GeneralParameterDescriptorPanel>(); this.groupParameters = new LinkedList<GeneralParameterDescriptorPanel>(); for (GeneralParameterDescriptor param : descGroup.descriptors()) { GeneralParameterDescriptorPanel comp = null; if (param instanceof ParameterDescriptor) { comp = new JParameterDescriptorPanel((ParameterDescriptor) param, this, filter); this.simpleParameters.add(comp); } else if (param instanceof ParameterDescriptorGroup) { comp = new JParameterDescriptorGroupPanel((ParameterDescriptorGroup) param, filter, this, focusListener); this.groupParameters.add(comp); } } //sort in alphabetical order using parameters code Collections.sort(simpleParameters); Collections.sort(groupParameters); initComponents(); paddingPanel.setBorder(new EmptyBorder(5, 28, 5, 28)); //disable add/remove button if group not editable/removable guiRemoveParamBtn.setEnabled(!rootGroup && removable); guiNewGroupBtn.setEnabled(editable); guiNewParamBtn.setEnabled(editable); //expender init guiExpenderBtn.setText(null); guiExpenderBtn.setIcon(CARET_DOWN); //ToolTipText on buttons. guiExpenderBtn.setToolTipText(MessageBundle.format("parameters_collapse")); guiNewGroupBtn.setToolTipText(MessageBundle.format("parameters_addNewGroupParameter")); guiNewParamBtn.setToolTipText(MessageBundle.format("parameters_addNewSimpleParameter")); guiRemoveParamBtn.setToolTipText(MessageBundle.format("parameters_removeParameter")); //label init guiGroupNameLbl.setText(code); guiGroupNameLbl.setCursor(new Cursor(Cursor.HAND_CURSOR)); guiGroupNameLbl.addMouseListener(this); updateContent(); } @Override public boolean isEditable() { return !rootGroup && editable; } public int getMinOccurs() { return minOccurs; } public void setMinOccurs(int minOccurs) { this.minOccurs = minOccurs; } public int getMaxOccurs() { return maxOccurs; } public void setMaxOccurs(int maxOccurs) { this.maxOccurs = 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(); guiRemoveParamBtn = new FontIconJButton(FontAwesomeIcons.ICON_MINUS_CIRCLE, 18, Color.RED); guiNewGroupBtn = new FontIconJButton(FontAwesomeIcons.ICON_PLUS_CIRCLE, 18, Color.BLACK); guiNewParamBtn = new FontIconJButton(FontAwesomeIcons.ICON_PLUS, 18, Color.BLACK); bottomPanel = new javax.swing.JPanel(); paddingPanel = new javax.swing.JPanel(); parametersContainerPanel = new javax.swing.JPanel(); setLayout(new java.awt.BorderLayout()); topPanel.setLayout(new java.awt.BorderLayout()); topLeftPanel.setAlignmentX(0.0F); 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) .addComponent(guiExpenderBtn) ); topLeftPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {guiExpenderBtn, guiGroupNameLbl}); topPanel.add(topLeftPanel, java.awt.BorderLayout.LINE_START); guiRemoveParamBtn.setBorderPainted(false); guiRemoveParamBtn.setContentAreaFilled(false); guiRemoveParamBtn.setFocusable(false); guiRemoveParamBtn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { guiRemoveParamBtnActionPerformed(evt); } }); 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); } }); guiNewParamBtn.setBorderPainted(false); guiNewParamBtn.setContentAreaFilled(false); guiNewParamBtn.setFocusable(false); guiNewParamBtn.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { guiNewParamBtnActionPerformed(evt); } }); javax.swing.GroupLayout topRightPanelLayout = new javax.swing.GroupLayout(topRightPanel); topRightPanel.setLayout(topRightPanelLayout); topRightPanelLayout.setHorizontalGroup( topRightPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(topRightPanelLayout.createSequentialGroup() .addContainerGap(18, Short.MAX_VALUE) .addComponent(guiNewParamBtn) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(guiNewGroupBtn) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(guiRemoveParamBtn)) ); topRightPanelLayout.setVerticalGroup( topRightPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(topRightPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.CENTER) .addComponent(guiNewGroupBtn) .addComponent(guiRemoveParamBtn) .addComponent(guiNewParamBtn)) ); topRightPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {guiNewGroupBtn, guiNewParamBtn, guiRemoveParamBtn}); topPanel.add(topRightPanel, java.awt.BorderLayout.LINE_END); add(topPanel, java.awt.BorderLayout.PAGE_START); bottomPanel.setLayout(new java.awt.BorderLayout()); paddingPanel.setLayout(new java.awt.BorderLayout()); parametersContainerPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); parametersContainerPanel.setLayout(new java.awt.GridBagLayout()); paddingPanel.add(parametersContainerPanel, java.awt.BorderLayout.PAGE_START); bottomPanel.add(paddingPanel, 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 expended = !expended; if (expended) { 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 /** * Fire event to parent JParameterDescriptorGroupPanel * @param evt */ private void guiRemoveParamBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_guiRemoveParamBtnActionPerformed firePropertyChange(JParameterDescriptorsEditor.PARAMETER_REMOVED_EVENT, this, false); }//GEN-LAST:event_guiRemoveParamBtnActionPerformed /** * Add new JParameterDescriptorGroupPanel to children. * @param evt */ private void guiNewGroupBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_guiNewGroupBtnActionPerformed final ParameterDescriptorGroup newGroup = new ParameterBuilder().addName(nextPrefixCode(GROUP_PREFIX)).createGroup(); final JParameterDescriptorGroupPanel groupPanel = new JParameterDescriptorGroupPanel(newGroup, null, this, focusListener); groupParameters.add(groupPanel); updateContent(); groupPanel.setSelected(true); firePropertyChange(JParameterDescriptorsEditor.DESCIPTOR_CHANGE_EVENT, null, newGroup); }//GEN-LAST:event_guiNewGroupBtnActionPerformed /** * Add new JParameterDescriptorPanel to children. * @param evt */ private void guiNewParamBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_guiNewParamBtnActionPerformed final ParameterDescriptor newDesc = new ParameterBuilder() .addName(nextPrefixCode(PARAM_PREFIX)) .create(String.class, null); final JParameterDescriptorPanel panel = new JParameterDescriptorPanel(newDesc, this, null); simpleParameters.add(panel); updateContent(); panel.setSelected(true); firePropertyChange(JParameterDescriptorsEditor.DESCIPTOR_CHANGE_EVENT, null, newDesc); }//GEN-LAST:event_guiNewParamBtnActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel bottomPanel; private javax.swing.JButton guiExpenderBtn; private javax.swing.JLabel guiGroupNameLbl; private javax.swing.JButton guiNewGroupBtn; private javax.swing.JButton guiNewParamBtn; private javax.swing.JButton guiRemoveParamBtn; private javax.swing.JPanel paddingPanel; private javax.swing.JPanel parametersContainerPanel; 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); //clear parametersContainerPanel.removeAll(); final GridBagConstraints constraint = new GridBagConstraints(); int index = 0; //first all simple parameters for (GeneralParameterDescriptorPanel param : simpleParameters) { if (param != null) { constraint.gridx = 0; constraint.gridy = index; constraint.weightx = 1.0; constraint.weighty = 0.0; constraint.fill = GridBagConstraints.BOTH; //add to panel param.addPropertyChangeListener(focusListener); //focusListener param.addPropertyChangeListener(this); //removeListener parametersContainerPanel.add(param, constraint); index++; } } //finish with group parameters for (GeneralParameterDescriptorPanel param : groupParameters) { if (param != null) { constraint.gridx = 0; constraint.gridy = index; constraint.weightx = 1.0; constraint.weighty = 0.0; constraint.fill = GridBagConstraints.BOTH; //add to panel param.addPropertyChangeListener(focusListener); //focusListener param.addPropertyChangeListener(this); //removeListener parametersContainerPanel.add(param, constraint); index++; } } this.revalidate(); } /** * Generate next unused prefix code. * * @param prefix * @return prefix string + index */ private String nextPrefixCode(final String prefix){ int i=1; incloop: for(;;i++){ if (PARAM_PREFIX.equals(prefix)) { for (GeneralParameterDescriptorPanel param : simpleParameters) { if( (prefix+i).equalsIgnoreCase(param.getCode())){ continue incloop; } } } else { for (GeneralParameterDescriptorPanel param : groupParameters) { if( (prefix+i).equalsIgnoreCase(param.getCode())){ continue incloop; } } } break incloop; } return prefix+i; } /** * Check if input code String is a already used by another parameter or not. * * @param code String to test * @param ignore GeneralParameterDescriptorPanel to ignore for test. * @return true if code is free and false otherwise. */ public boolean isValidCode(final String code, final GeneralParameterDescriptorPanel ignore) { if (code == null) return false; boolean valid = true; for (final GeneralParameterDescriptorPanel param : simpleParameters) { if (!param.equals(ignore) && code.equalsIgnoreCase(param.getCode())) { valid = false; } } for (final GeneralParameterDescriptorPanel param : groupParameters) { if (!param.equals(ignore) && code.equalsIgnoreCase(param.getCode())) { valid = false; } } return valid; } @Override public GeneralParameterDescriptor getDescriptor() { final List<GeneralParameterDescriptor> descriptors = new ArrayList<GeneralParameterDescriptor>(); for (GeneralParameterDescriptorPanel param : simpleParameters) { descriptors.add(param.getDescriptor()); } for (GeneralParameterDescriptorPanel param : groupParameters) { descriptors.add(param.getDescriptor()); } final InternationalString remark = remarks != null ? new SimpleInternationalString(remarks) : null; return ParametersExt.createParameterDescriptorGroup(code, remark, minOccurs, maxOccurs, descriptors); } @Override public void setBackgroundColor(final Color color) { topPanel.setBackground(color); topLeftPanel.setBackground(color); topRightPanel.setBackground(color); paddingPanel.setBackground(color); } @Override public void propertyChange(PropertyChangeEvent evt) { //Parameter removed event //If parameter to remove isn't already removed, try to remove it and forward event. if (JParameterDescriptorsEditor.PARAMETER_REMOVED_EVENT.equals(evt.getPropertyName())) { boolean removed = (Boolean)evt.getNewValue(); final GeneralParameterDescriptorPanel toRemove = (GeneralParameterDescriptorPanel)evt.getOldValue(); if (simpleParameters.contains(toRemove) && !removed) { toRemove.setSelected(false); SwingUtilities.removeAllPropertyChangeListeners(toRemove); simpleParameters.remove(toRemove); updateContent(); removed = true; this.setSelected(true); } if (groupParameters.contains(toRemove) && !removed) { toRemove.setSelected(false); SwingUtilities.removeAllPropertyChangeListeners(toRemove); groupParameters.remove(toRemove); updateContent(); removed = true; this.setSelected(true); } firePropertyChange(JParameterDescriptorsEditor.PARAMETER_REMOVED_EVENT, evt.getOldValue(), removed); firePropertyChange(JParameterDescriptorsEditor.DESCIPTOR_CHANGE_EVENT, null, this); } //Parameter change event. if (JParameterDescriptorsEditor.PARAMETER_CHANGE_EVENT.equals(evt.getPropertyName())) { this.revalidate(); } //forward event if (JParameterDescriptorsEditor.DESCIPTOR_CHANGE_EVENT.equals(evt.getPropertyName())) { firePropertyChange(JParameterDescriptorsEditor.DESCIPTOR_CHANGE_EVENT, null, this); } } /** * Sort GeneralParameterDescriptorPanel by first JParameterDescriptorPanel and then JParameterDescriptorGroupPanel. */ private class ParameterPanelComparator implements Comparator<GeneralParameterDescriptorPanel> { @Override public int compare(GeneralParameterDescriptorPanel o1, GeneralParameterDescriptorPanel o2) { if (o1 != null && o2 != null) { if (o1 instanceof JParameterDescriptorPanel) { if (o2 instanceof JParameterDescriptorPanel) { return o1.compareTo(o2); } else { return -1; } } else { if (o2 instanceof JParameterDescriptorPanel) { return 1; } else { return o1.compareTo(o2); } } } if (o1 == null) return -1; if (o2 == null) return 1; return 0; } } }