package org.exist.client.xacml; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.Spring; import javax.swing.SpringLayout; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.text.BadLocationException; import javax.swing.text.Document; import javax.swing.text.JTextComponent; import org.exist.client.ClientFrame; import com.sun.xacml.ParsingException; import com.sun.xacml.UnknownIdentifierException; import com.sun.xacml.attr.AttributeDesignator; import com.sun.xacml.attr.AttributeFactory; import com.sun.xacml.attr.AttributeValue; public class MatchEditor extends JPanel implements ActionListener, DocumentListener { private static final String EMPTY_TEXT = "Select an attribute to edit"; private static final int MAXIMUM_BOX_WIDTH = 450; private AttributeDesignator attribute; private JLabel label; private JComboBox functionBox; private JComboBox valueBox; private Abbreviator abbrev; private List listeners = new ArrayList(2); private List attributeHandlers = new ArrayList(2); private Object currentFunction; private Object currentValue; private MatchEditor() {} public MatchEditor(Abbreviator abbrev) { this.abbrev = abbrev; setup(); } private void setup() { SpringLayout layout = new SpringLayout(); setLayout(layout); setOpaque(true); label = new JLabel(EMPTY_TEXT); functionBox = new JComboBox(); functionBox.setEditable(false); functionBox.setMaximumSize(restrictWidth(functionBox.getMaximumSize())); valueBox = new JComboBox(); valueBox.setEditable(true); valueBox.setMaximumSize(restrictWidth(functionBox.getMaximumSize())); Component comp = valueBox.getEditor().getEditorComponent(); if(comp instanceof JTextComponent) ((JTextComponent)comp).getDocument().addDocumentListener(this); setBoxesVisible(false); add(label); add(functionBox); add(valueBox); Spring constant6 = Spring.constant(6); layout.putConstraint(SpringLayout.NORTH, label, constant6, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.NORTH, functionBox, constant6, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.NORTH, valueBox, constant6, SpringLayout.NORTH, this); Spring bottom = layout.getConstraint(SpringLayout.SOUTH, label); bottom = Spring.max(bottom, layout.getConstraint(SpringLayout.SOUTH, functionBox)); bottom = Spring.max(bottom, layout.getConstraint(SpringLayout.SOUTH, valueBox)); layout.putConstraint(SpringLayout.SOUTH, this, bottom, SpringLayout.NORTH, this); layout.putConstraint(SpringLayout.WEST, functionBox, constant6, SpringLayout.EAST, label); layout.putConstraint(SpringLayout.WEST, valueBox, constant6, SpringLayout.EAST, functionBox); layout.putConstraint(SpringLayout.EAST, this, Spring.constant(6,6,Short.MAX_VALUE), SpringLayout.EAST, valueBox); } public void setMatch(AttributeDesignator attribute, URI functionId, AttributeValue value) { valueBox.removeActionListener(this); functionBox.removeActionListener(this); Component comp = valueBox.getEditor().getEditorComponent(); Document doc = null; if(comp instanceof JTextComponent) { doc = ((JTextComponent)comp).getDocument(); doc.removeDocumentListener(this); } this.attribute = attribute; if(attribute == null) { label.setText(EMPTY_TEXT); setBoxesVisible(false); return; } URI dataType = attribute.getType(); label.setText(abbrev.getAbbreviatedId(attribute.getId()) + " (" + abbrev.getAbbreviatedType(dataType) + ")"); Set targetFunctions = abbrev.getAbbreviatedTargetFunctions(dataType); for(Iterator it = attributeHandlers.iterator(); it.hasNext();) ((AttributeHandler)it.next()).filterFunctions(targetFunctions, attribute); functionBox.setModel(new DefaultComboBoxModel(targetFunctions.toArray())); if(functionId == null) { if(functionBox.getItemCount() > 0) functionBox.setSelectedIndex(0); } else functionBox.setSelectedItem(abbrev.getAbbreviatedTargetFunctionId(functionId, dataType)); functionBox.setMaximumSize(restrictWidth(functionBox.getPreferredSize())); valueBox.setEditable(true); Set allowedValues = new TreeSet(); for(Iterator it = attributeHandlers.iterator(); it.hasNext();) { if(!((AttributeHandler)it.next()).getAllowedValues(allowedValues, attribute)) { valueBox.setEditable(false); break; } } valueBox.setModel(new DefaultComboBoxModel(allowedValues.toArray())); if(valueBox.isEditable()) { Dimension max = valueBox.getMaximumSize(); max.width = MAXIMUM_BOX_WIDTH; valueBox.setMaximumSize(max); } else valueBox.setMaximumSize(restrictWidth(valueBox.getMaximumSize())); valueBox.setSelectedItem((value == null) ? null : value.encode()); setBoxesVisible(true); currentValue = valueBox.getSelectedItem(); currentFunction = functionBox.getSelectedItem(); valueBox.addActionListener(this); functionBox.addActionListener(this); if(doc != null) doc.addDocumentListener(this); } private Dimension restrictWidth(Dimension size) { if(size.width > MAXIMUM_BOX_WIDTH) size.width = MAXIMUM_BOX_WIDTH; return size; } private void setBoxesVisible(boolean b) { functionBox.setVisible(b); valueBox.setVisible(b); } public URI getFunctionId() { return (currentFunction == null) ? null : abbrev.getFullFunctionId((String)currentFunction, attribute.getType()); } public AttributeValue getValue() { if(attribute == null || currentValue == null) return null; AttributeFactory factory = AttributeFactory.getInstance(); try { String textValue = currentValue.toString(); if(textValue == null || textValue.length() == 0) return null; AttributeValue value = factory.createValue(attribute.getType(), textValue); for(Iterator it = attributeHandlers.iterator(); it.hasNext();) ((AttributeHandler)it.next()).checkUserValue(value, attribute); return value; } catch(UnknownIdentifierException e) { ClientFrame.showErrorMessage("Invalid attribute type '" + attribute.getType() + "'", e); return null; } catch (ParsingException e) { ClientFrame.showErrorMessage("Invalid value '" + currentValue + "'", e); return null; } } public AttributeDesignator getAttribute() { return attribute; } public void addAttributeHandler(AttributeHandler ah) { if(ah == null) return; if(attributeHandlers == null) attributeHandlers = new ArrayList(); attributeHandlers.add(ah); } public void removeAttributeHandler(AttributeHandler ah) { if(ah == null || attributeHandlers == null) return; attributeHandlers.remove(ah); } public void actionPerformed(ActionEvent event) { Object source = event.getSource(); if(source == functionBox) currentFunction = functionBox.getSelectedItem(); else if(source == valueBox) currentValue = valueBox.getSelectedItem(); else return; fireChanged(); } private void fireChanged() { ChangeEvent event = new ChangeEvent(this); for(Iterator it = listeners.iterator(); it.hasNext();) ((ChangeListener)it.next()).stateChanged(event); } public void addChangeListener(ChangeListener listener) { if(listener != null) listeners.add(listener); } public void removeChangeListener(ChangeListener listener) { if(listeners != null) listeners.remove(listeners); } private void documentUpdated(DocumentEvent event) { Document doc = event.getDocument(); try { currentValue = doc.getText(0, doc.getLength()); } catch (BadLocationException e) { return; } fireChanged(); } public void changedUpdate(DocumentEvent event) { documentUpdated(event); } public void insertUpdate(DocumentEvent event) { documentUpdated(event); } public void removeUpdate(DocumentEvent event) { documentUpdated(event); } }