001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2008-2010 Sun Microsystems, Inc.
025 *      Portions Copyright 2014-2015 ForgeRock AS
026 */
027package org.opends.guitools.controlpanel.ui;
028
029import static org.opends.messages.AdminToolMessages.*;
030
031import java.awt.Component;
032import java.awt.GridBagConstraints;
033import java.awt.GridBagLayout;
034import java.awt.event.ItemEvent;
035import java.awt.event.ItemListener;
036import java.io.File;
037import java.util.ArrayList;
038import java.util.Arrays;
039import java.util.HashMap;
040import java.util.LinkedHashSet;
041import java.util.List;
042import java.util.Map;
043import java.util.Set;
044import java.util.SortedSet;
045import java.util.TreeSet;
046
047import javax.swing.DefaultComboBoxModel;
048import javax.swing.JCheckBox;
049import javax.swing.JComboBox;
050import javax.swing.JLabel;
051import javax.swing.JPanel;
052import javax.swing.JTextField;
053import javax.swing.SwingUtilities;
054import javax.swing.event.ChangeEvent;
055import javax.swing.event.ChangeListener;
056
057import org.forgerock.i18n.LocalizableMessage;
058import org.forgerock.i18n.LocalizableMessageBuilder;
059import org.forgerock.opendj.ldap.schema.AttributeUsage;
060import org.forgerock.opendj.ldap.schema.MatchingRule;
061import org.opends.guitools.controlpanel.datamodel.ServerDescriptor;
062import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
063import org.opends.guitools.controlpanel.event.ConfigurationElementCreatedListener;
064import org.opends.guitools.controlpanel.task.NewSchemaElementsTask;
065import org.opends.guitools.controlpanel.task.Task;
066import org.opends.guitools.controlpanel.ui.components.BasicExpander;
067import org.opends.guitools.controlpanel.ui.renderer.SchemaElementComboBoxCellRenderer;
068import org.opends.guitools.controlpanel.util.LowerCaseComparator;
069import org.opends.guitools.controlpanel.util.Utilities;
070import org.forgerock.opendj.ldap.schema.Syntax;
071import org.opends.server.config.ConfigConstants;
072import org.opends.server.types.AttributeType;
073import org.opends.server.types.ObjectClass;
074import org.opends.server.types.Schema;
075import org.opends.server.util.ServerConstants;
076import org.opends.server.util.StaticUtils;
077
078/**
079 * The panel displayed when the user wants to define a new attribute in the
080 * schema.
081 */
082public class NewAttributePanel extends StatusGenericPanel
083{
084  private static final long serialVersionUID = 2340170241535771321L;
085
086  private static final LocalizableMessage NO_PARENT = INFO_CTRL_PANEL_NO_PARENT_FOR_ATTRIBUTE.get();
087  private static final LocalizableMessage NO_MATCHING_RULE = INFO_CTRL_PANEL_NO_MATCHING_RULE_FOR_ATTRIBUTE.get();
088
089  private final JLabel lName = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_NAME_LABEL.get());
090  private final JLabel lParent = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_PARENT_LABEL.get());
091  private final JLabel lOID = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_OID_LABEL.get());
092  private final JLabel lAliases = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_ALIASES_LABEL.get());
093  private final JLabel lOrigin = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_ORIGIN_LABEL.get());
094  private final JLabel lFile = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_FILE_LABEL.get());
095  private final JLabel lDescription = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_DESCRIPTION_LABEL.get());
096  private final JLabel lUsage = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_USAGE_LABEL.get());
097  private final JLabel lSyntax = Utilities.createPrimaryLabel(INFO_CTRL_PANEL_ATTRIBUTE_SYNTAX_LABEL.get());
098  private final JLabel lApproximate = Utilities.createPrimaryLabel(
099      INFO_CTRL_PANEL_ATTRIBUTE_APPROXIMATE_MATCHING_RULE_LABEL.get());
100  private final JLabel lEquality = Utilities.createPrimaryLabel(
101      INFO_CTRL_PANEL_ATTRIBUTE_EQUALITY_MATCHING_RULE_LABEL.get());
102  private final JLabel lOrdering = Utilities.createPrimaryLabel(
103      INFO_CTRL_PANEL_ATTRIBUTE_ORDERING_MATCHING_RULE_LABEL.get());
104  private final JLabel lSubstring = Utilities.createPrimaryLabel(
105      INFO_CTRL_PANEL_ATTRIBUTE_SUBSTRING_MATCHING_RULE_LABEL.get());
106  private final JLabel lType = Utilities.createPrimaryLabel();
107
108  private final JLabel[] labels = { lName, lParent, lOID, lAliases, lOrigin, lFile, lDescription, lUsage, lSyntax,
109    lApproximate, lEquality, lOrdering, lSubstring, lType };
110
111  private final JTextField name = Utilities.createMediumTextField();
112  private final JComboBox parent = Utilities.createComboBox();
113  private final JTextField oid = Utilities.createMediumTextField();
114  private final JTextField aliases = Utilities.createLongTextField();
115  private final JTextField description = Utilities.createLongTextField();
116  private final JTextField origin = Utilities.createLongTextField();
117  private final JTextField file = Utilities.createLongTextField();
118  private final JComboBox<AttributeUsage> usage = Utilities.createComboBox();
119  private final JComboBox syntax = Utilities.createComboBox();
120  private final JComboBox approximate = Utilities.createComboBox();
121  private final JComboBox equality = Utilities.createComboBox();
122  private final JComboBox ordering = Utilities.createComboBox();
123  private final JComboBox substring = Utilities.createComboBox();
124  private final JCheckBox nonModifiable = Utilities.createCheckBox(
125      INFO_CTRL_PANEL_ATTRIBUTE_NON_MODIFIABLE_LABEL.get());
126  private final JCheckBox singleValued = Utilities.createCheckBox(INFO_CTRL_PANEL_ATTRIBUTE_SINGLE_VALUED_LABEL.get());
127  private final JCheckBox collective = Utilities.createCheckBox(INFO_CTRL_PANEL_ATTRIBUTE_COLLECTIVE_LABEL.get());
128  private final JCheckBox obsolete = Utilities.createCheckBox(INFO_CTRL_PANEL_ATTRIBUTE_OBSOLETE_LABEL.get());
129
130  private Schema schema;
131
132  private final Component relativeComponent;
133
134  /**
135   * Constructor of the new attribute panel.
136   *
137   * @param relativeComponent
138   *          the component relative to which the dialog containing this panel
139   *          must be centered.
140   */
141  public NewAttributePanel(Component relativeComponent)
142  {
143    this.relativeComponent = relativeComponent;
144    createLayout();
145  }
146
147  @Override
148  public LocalizableMessage getTitle()
149  {
150    return INFO_CTRL_PANEL_NEW_ATTRIBUTE_PANEL_TITLE.get();
151  }
152
153  @Override
154  public Component getPreferredFocusComponent()
155  {
156    return name;
157  }
158
159  @Override
160  public void configurationChanged(ConfigurationChangeEvent ev)
161  {
162    List<Syntax> newSyntaxes = new ArrayList<>();
163    final ServerDescriptor desc = ev.getNewDescriptor();
164    Schema s = desc.getSchema();
165
166    final boolean firstSchema = schema == null;
167    final boolean[] repack = { firstSchema };
168    final boolean[] error = { false };
169
170    boolean schemaChanged;
171    if (schema != null && s != null)
172    {
173      schemaChanged = !ServerDescriptor.areSchemasEqual(s, schema);
174    }
175    else if (schema == null && s != null)
176    {
177      schemaChanged = true;
178    }
179    else if (s == null && schema != null)
180    {
181      schemaChanged = false;
182    }
183    else
184    {
185      schemaChanged = false;
186    }
187    if (schemaChanged)
188    {
189      schema = s;
190      Map<String, Syntax> syntaxNameMap = new HashMap<>();
191
192      for (String key : schema.getSyntaxes().keySet())
193      {
194        Syntax syntax = schema.getSyntax(key);
195        String name = syntax.getName();
196        if (name == null)
197        {
198          name = syntax.getOID();
199        }
200        syntaxNameMap.put(name, syntax);
201      }
202
203      SortedSet<String> orderedKeys = new TreeSet<>(new LowerCaseComparator());
204      orderedKeys.addAll(syntaxNameMap.keySet());
205      for (String key : orderedKeys)
206      {
207        newSyntaxes.add(syntaxNameMap.get(key));
208      }
209      updateComboBoxModel(newSyntaxes, (DefaultComboBoxModel) syntax.getModel());
210
211      Map<String, AttributeType> attributeNameMap = new HashMap<>();
212      for (String key : schema.getAttributeTypes().keySet())
213      {
214        AttributeType attr = schema.getAttributeType(key);
215        attributeNameMap.put(attr.getNameOrOID(), attr);
216      }
217      orderedKeys.clear();
218      orderedKeys.addAll(attributeNameMap.keySet());
219      List<Object> newParents = new ArrayList<>();
220      for (String key : orderedKeys)
221      {
222        newParents.add(attributeNameMap.get(key));
223      }
224      newParents.add(0, NO_PARENT);
225      updateComboBoxModel(newParents, (DefaultComboBoxModel) parent.getModel());
226
227      final List<MatchingRule> availableMatchingRules = new ArrayList<>();
228      final Map<String, MatchingRule> matchingRuleNameMap = new HashMap<>();
229      for (String key : schema.getMatchingRules().keySet())
230      {
231        MatchingRule rule = schema.getMatchingRule(key);
232        matchingRuleNameMap.put(rule.getNameOrOID(), rule);
233      }
234
235      orderedKeys.clear();
236      orderedKeys.addAll(matchingRuleNameMap.keySet());
237      for (final String key : orderedKeys)
238      {
239        availableMatchingRules.add(matchingRuleNameMap.get(key));
240      }
241
242      final JComboBox[] combos = { approximate, equality, ordering, substring };
243      for (int i = 0; i < combos.length; i++)
244      {
245        final DefaultComboBoxModel model = (DefaultComboBoxModel) combos[i].getModel();
246        final List<Object> el = new ArrayList<Object>(availableMatchingRules);
247        el.add(0, model.getSize() == 0 ? NO_MATCHING_RULE : model.getElementAt(0));
248        updateComboBoxModel(el, model);
249      }
250    }
251    else if (schema == null)
252    {
253      updateErrorPane(errorPane,
254          ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_SUMMARY.get(),
255          ColorAndFontConstants.errorTitleFont,
256          ERR_CTRL_PANEL_SCHEMA_NOT_FOUND_DETAILS.get(),
257          ColorAndFontConstants.defaultFont);
258      repack[0] = true;
259      error[0] = true;
260    }
261    SwingUtilities.invokeLater(new Runnable()
262    {
263      @Override
264      public void run()
265      {
266        setEnabledOK(!error[0]);
267        errorPane.setVisible(error[0]);
268        if (firstSchema)
269        {
270          for (int i = 0; i < syntax.getModel().getSize(); i++)
271          {
272            Syntax syn = (Syntax) syntax.getModel().getElementAt(i);
273            if ("DirectoryString".equals(syn.getName()))
274            {
275              syntax.setSelectedIndex(i);
276              break;
277            }
278          }
279        }
280        else
281        {
282          updateDefaultMatchingRuleNames();
283        }
284
285        if (repack[0])
286        {
287          packParentDialog();
288          if (relativeComponent != null)
289          {
290            Utilities.centerGoldenMean(Utilities.getParentDialog(NewAttributePanel.this), relativeComponent);
291          }
292        }
293      }
294    });
295    if (!error[0])
296    {
297      updateErrorPaneAndOKButtonIfAuthRequired(desc,
298          isLocal() ? INFO_CTRL_PANEL_AUTHENTICATION_REQUIRED_TO_CREATE_ATTRIBUTE_SUMMARY.get()
299                    : INFO_CTRL_PANEL_CANNOT_CONNECT_TO_REMOTE_DETAILS.get(desc.getHostname()));
300    }
301  }
302
303  @Override
304  public void okClicked()
305  {
306    List<LocalizableMessage> errors = new ArrayList<>();
307    for (JLabel label : labels)
308    {
309      setPrimaryValid(label);
310    }
311    String n = getAttributeName();
312    LocalizableMessageBuilder err = new LocalizableMessageBuilder();
313    if (n.length() == 0)
314    {
315      errors.add(ERR_CTRL_PANEL_ATTRIBUTE_NAME_REQUIRED.get());
316      setPrimaryInvalid(lName);
317    }
318    else if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
319    {
320      errors.add(ERR_CTRL_PANEL_INVALID_ATTRIBUTE_NAME.get(err));
321      setPrimaryInvalid(lName);
322      err = new LocalizableMessageBuilder();
323    }
324    else
325    {
326      LocalizableMessage elementType = getSchemaElementType(n, schema);
327      if (elementType != null)
328      {
329        errors.add(ERR_CTRL_PANEL_ATTRIBUTE_NAME_ALREADY_IN_USE.get(n, elementType));
330        setPrimaryInvalid(lName);
331      }
332    }
333
334    n = oid.getText().trim();
335    if (n.length() > 0)
336    {
337      if (!StaticUtils.isValidSchemaElement(n, 0, n.length(), err))
338      {
339        errors.add(ERR_CTRL_PANEL_OID_NOT_VALID.get(err));
340        setPrimaryInvalid(lOID);
341        err = new LocalizableMessageBuilder();
342      }
343      else
344      {
345        LocalizableMessage elementType = getSchemaElementType(n, schema);
346        if (elementType != null)
347        {
348          errors.add(ERR_CTRL_PANEL_OID_ALREADY_IN_USE.get(n, elementType));
349          setPrimaryInvalid(lOID);
350        }
351      }
352    }
353
354    if (aliases.getText().trim().length() > 0)
355    {
356      String[] al = aliases.getText().split(",");
357      if (al.length > 0)
358      {
359        for (String alias : al)
360        {
361          if (alias.trim().length() == 0)
362          {
363            errors.add(ERR_CTRL_PANEL_EMPTY_ALIAS.get());
364            setPrimaryInvalid(lAliases);
365          }
366          else
367          {
368            LocalizableMessage elementType = getSchemaElementType(alias, schema);
369            if (elementType != null)
370            {
371              errors.add(ERR_CTRL_PANEL_ALIAS_ALREADY_IN_USE.get(n, elementType));
372              setPrimaryInvalid(lAliases);
373            }
374          }
375        }
376      }
377    }
378
379    setPrimaryValid(lUsage);
380    if (nonModifiable.isSelected() && AttributeUsage.USER_APPLICATIONS.equals(usage.getSelectedItem()))
381    {
382      errors.add(ERR_NON_MODIFIABLE_CANNOT_BE_USER_APPLICATIONS.get());
383      setPrimaryInvalid(lUsage);
384    }
385
386    ProgressDialog dlg = new ProgressDialog(Utilities.createFrame(), Utilities.getParentDialog(this),
387        INFO_CTRL_PANEL_NEW_ATTRIBUTE_PANEL_TITLE.get(), getInfo());
388    NewSchemaElementsTask newTask = null;
389    if (errors.isEmpty())
390    {
391      Set<AttributeType> attributes = new LinkedHashSet<>();
392      attributes.add(getAttribute());
393      Set<ObjectClass> ocs = new LinkedHashSet<>(0);
394      newTask = new NewSchemaElementsTask(getInfo(), dlg, ocs, attributes);
395      for (Task task : getInfo().getTasks())
396      {
397        task.canLaunch(newTask, errors);
398      }
399      for (ConfigurationElementCreatedListener listener : getConfigurationElementCreatedListeners())
400      {
401        newTask.addConfigurationElementCreatedListener(listener);
402      }
403    }
404    if (errors.isEmpty())
405    {
406      String attrName = getAttributeName();
407      launchOperation(newTask,
408                      INFO_CTRL_PANEL_CREATING_ATTRIBUTE_SUMMARY.get(attrName),
409                      INFO_CTRL_PANEL_CREATING_ATTRIBUTE_COMPLETE.get(),
410                      INFO_CTRL_PANEL_CREATING_ATTRIBUTE_SUCCESSFUL.get(attrName),
411                      ERR_CTRL_PANEL_CREATING_ATTRIBUTE_ERROR_SUMMARY.get(),
412                      ERR_CTRL_PANEL_CREATING_ATTRIBUTE_ERROR_DETAILS.get(attrName),
413                      null,
414                      dlg);
415      dlg.setVisible(true);
416      name.setText("");
417      oid.setText("");
418      description.setText("");
419      aliases.setText("");
420      name.grabFocus();
421      Utilities.getParentDialog(this).setVisible(false);
422    }
423    else
424    {
425      displayErrorDialog(errors);
426    }
427  }
428
429  /**
430   * Returns the message representing the schema element type.
431   *
432   * @param name
433   *          the name of the schema element.
434   * @param schema
435   *          the schema.
436   * @return the message representing the schema element type.
437   */
438  static LocalizableMessage getSchemaElementType(String name, Schema schema)
439  {
440    final String lowerCase = name.toLowerCase();
441    if (schema.getAttributeType(lowerCase) != null)
442    {
443      return INFO_CTRL_PANEL_TYPE_ATTRIBUTE.get();
444    }
445    else if (schema.getObjectClass(lowerCase) != null)
446    {
447      return INFO_CTRL_PANEL_TYPE_OBJECT_CLASS.get();
448    }
449    else if (schema.getSyntax(lowerCase) != null)
450    {
451      return INFO_CTRL_PANEL_TYPE_ATTRIBUTE_SYNTAX.get();
452    }
453    else if (schema.getMatchingRule(lowerCase) != null)
454    {
455      return INFO_CTRL_PANEL_TYPE_MATCHING_RULE.get();
456    }
457
458    for (Syntax attr : schema.getSyntaxes().values())
459    {
460      if (name.equalsIgnoreCase(attr.getName()))
461      {
462        return INFO_CTRL_PANEL_TYPE_ATTRIBUTE_SYNTAX.get();
463      }
464    }
465
466    for (MatchingRule rule : schema.getMatchingRules().values())
467    {
468      String n = rule.getNameOrOID();
469      if (n != null && n.equalsIgnoreCase(name))
470      {
471        return INFO_CTRL_PANEL_TYPE_MATCHING_RULE.get();
472      }
473    }
474
475    return null;
476  }
477
478  /** Creates the layout of the panel (but the contents are not populated here). */
479  private void createLayout()
480  {
481    GridBagConstraints gbc = new GridBagConstraints();
482    Utilities.setRequiredIcon(lName);
483
484    gbc.gridwidth = 2;
485    gbc.gridy = 0;
486    addErrorPane(gbc);
487
488    gbc.gridy++;
489    gbc.gridwidth = 1;
490    gbc.weighty = 0.0;
491    gbc.gridx = 1;
492    gbc.anchor = GridBagConstraints.EAST;
493    gbc.fill = GridBagConstraints.NONE;
494    JLabel requiredLabel = createRequiredLabel();
495    gbc.insets.bottom = 10;
496    add(requiredLabel, gbc);
497
498    gbc.gridy++;
499    gbc.fill = GridBagConstraints.HORIZONTAL;
500    gbc.anchor = GridBagConstraints.WEST;
501    gbc.insets.bottom = 0;
502
503    JComboBox[] comboBoxes = { parent, syntax, approximate, equality, ordering, substring };
504    LocalizableMessage[] defaultValues =
505        { NO_PARENT, LocalizableMessage.EMPTY, NO_MATCHING_RULE, NO_MATCHING_RULE, NO_MATCHING_RULE, NO_MATCHING_RULE };
506    SchemaElementComboBoxCellRenderer renderer = new SchemaElementComboBoxCellRenderer(syntax);
507    for (int i = 0; i < comboBoxes.length; i++)
508    {
509      DefaultComboBoxModel model = new DefaultComboBoxModel(new Object[] { defaultValues[i] });
510      comboBoxes[i].setModel(model);
511      comboBoxes[i].setRenderer(renderer);
512    }
513
514    DefaultComboBoxModel<AttributeUsage> model = new DefaultComboBoxModel<>();
515    for (AttributeUsage us : AttributeUsage.values())
516    {
517      model.addElement(us);
518    }
519    usage.setModel(model);
520    usage.setSelectedItem(AttributeUsage.USER_APPLICATIONS);
521    usage.setRenderer(renderer);
522
523    Component[] basicComps = { name, oid, description, syntax };
524    JLabel[] basicLabels = { lName, lOID, lDescription, lSyntax };
525    JLabel[] basicInlineHelp = new JLabel[] {
526      null, null, null, Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_SYNTAX_INLINE_HELP.get()) };
527    add(basicLabels, basicComps, basicInlineHelp, this, gbc);
528
529    BasicExpander[] expanders = new BasicExpander[] {
530          new BasicExpander(INFO_CTRL_PANEL_EXTRA_OPTIONS_EXPANDER.get()),
531          new BasicExpander(INFO_CTRL_PANEL_ATTRIBUTE_TYPE_OPTIONS_EXPANDER.get()),
532          new BasicExpander(INFO_CTRL_PANEL_MATCHING_RULE_OPTIONS_EXPANDER.get()) };
533
534    Component[][] comps = { { parent, aliases, origin, file },
535                            { usage, singleValued, nonModifiable, collective, obsolete },
536                            { approximate, equality, ordering, substring } };
537    JLabel[][] labels ={ { lParent, lAliases, lOrigin, lFile },
538                         { lUsage, lType, null, null, null },
539                         { lApproximate, lEquality, lOrdering, lSubstring } };
540    JLabel[][] inlineHelps = {
541          { null, Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_SEPARATED_WITH_COMMAS_HELP.get()), null,
542            Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_SCHEMA_FILE_ATTRIBUTE_HELP.get(File.separator)) },
543          { null, null, null, null, null, null },
544          { Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_MATCHING_RULE_APPROXIMATE_HELP.get()),
545            Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_MATCHING_RULE_EQUALITY_HELP.get()),
546            Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_MATCHING_RULE_ORDERING_HELP.get()),
547            Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_MATCHING_RULE_SUBSTRING_HELP.get()) } };
548    for (int i = 0; i < expanders.length; i++)
549    {
550      gbc.gridwidth = 2;
551      gbc.gridx = 0;
552      gbc.insets.left = 0;
553      add(expanders[i], gbc);
554      final JPanel p = new JPanel(new GridBagLayout());
555      gbc.insets.left = 15;
556      gbc.gridy++;
557      add(p, gbc);
558      gbc.gridy++;
559      p.setOpaque(false);
560
561      GridBagConstraints gbc1 = new GridBagConstraints();
562      gbc1.fill = GridBagConstraints.HORIZONTAL;
563      gbc1.gridy = 0;
564
565      add(labels[i], comps[i], inlineHelps[i], p, gbc1);
566      final BasicExpander expander = expanders[i];
567      ChangeListener changeListener = new ChangeListener()
568      {
569        @Override
570        public void stateChanged(ChangeEvent e)
571        {
572          p.setVisible(expander.isSelected());
573        }
574      };
575      expander.addChangeListener(changeListener);
576      expander.setSelected(false);
577      changeListener.stateChanged(null);
578    }
579    addBottomGlue(gbc);
580
581    ItemListener itemListener = new ItemListener()
582    {
583      @Override
584      public void itemStateChanged(ItemEvent ev)
585      {
586        if (ev.getStateChange() == ItemEvent.SELECTED)
587        {
588          updateDefaultMatchingRuleNames();
589          approximate.setSelectedIndex(0);
590          substring.setSelectedIndex(0);
591          equality.setSelectedIndex(0);
592          ordering.setSelectedIndex(0);
593        }
594      }
595    };
596    syntax.addItemListener(itemListener);
597
598    file.setText(ConfigConstants.FILE_USER_SCHEMA_ELEMENTS);
599  }
600
601  private void updateDefaultMatchingRuleNames()
602  {
603    Syntax syn = (Syntax) syntax.getSelectedItem();
604    if (syn != null)
605    {
606      MatchingRule[] rules = { syn.getApproximateMatchingRule(), syn.getSubstringMatchingRule(),
607        syn.getEqualityMatchingRule(), syn.getOrderingMatchingRule() };
608      JComboBox[] combos = { approximate, substring, equality, ordering };
609      for (int i = 0; i < rules.length; i++)
610      {
611        DefaultComboBoxModel model = (DefaultComboBoxModel) combos[i].getModel();
612        int index = combos[i].getSelectedIndex();
613        if (model.getSize() > 0)
614        {
615          model.removeElementAt(0);
616        }
617
618        final LocalizableMessage msg =
619            rules[i] != null ? INFO_CTRL_PANEL_DEFAULT_DEFINED_IN_SYNTAX.get(rules[i].getNameOrOID())
620                             : NO_MATCHING_RULE;
621        model.insertElementAt(msg, 0);
622        combos[i].setSelectedIndex(index);
623      }
624    }
625  }
626
627  private String getAttributeName()
628  {
629    return name.getText().trim();
630  }
631
632  private String getOID()
633  {
634    String o = oid.getText().trim();
635    if (o.length() == 0)
636    {
637      o = getAttributeName() + "-oid";
638    }
639    return o;
640  }
641
642  private List<String> getAliases()
643  {
644    List<String> al = new ArrayList<>();
645    String s = aliases.getText().trim();
646    if (s.length() > 0)
647    {
648      String[] a = s.split(",");
649      for (String alias : a)
650      {
651        al.add(alias.trim());
652      }
653    }
654    return al;
655  }
656
657  private List<String> getAllNames()
658  {
659    List<String> al = new ArrayList<>();
660    al.add(getAttributeName());
661    al.addAll(getAliases());
662    return al;
663  }
664
665  private AttributeType getSuperior()
666  {
667    Object o = parent.getSelectedItem();
668    if (NO_PARENT.equals(o))
669    {
670      return null;
671    }
672    return (AttributeType) o;
673  }
674
675  private MatchingRule getApproximateMatchingRule()
676  {
677    return getMatchingRule(approximate);
678  }
679
680  private MatchingRule getEqualityMatchingRule()
681  {
682    return getMatchingRule(equality);
683  }
684
685  private MatchingRule getSubstringMatchingRule()
686  {
687    return getMatchingRule(substring);
688  }
689
690  private MatchingRule getOrderingMatchingRule()
691  {
692    return getMatchingRule(ordering);
693  }
694
695  private MatchingRule getMatchingRule(JComboBox comboBox)
696  {
697    if (comboBox.getSelectedIndex() != 0)
698    {
699      return (MatchingRule) comboBox.getSelectedItem();
700    }
701    return null;
702  }
703
704  private Map<String, List<String>> getExtraProperties()
705  {
706    final Map<String, List<String>> map = new HashMap<>();
707    addExtraPropertyFromTextField(file, ServerConstants.SCHEMA_PROPERTY_FILENAME, map);
708    addExtraPropertyFromTextField(origin, ServerConstants.SCHEMA_PROPERTY_ORIGIN, map);
709    return map;
710  }
711
712  private void addExtraPropertyFromTextField(
713      final JTextField value, final String key, final Map<String, List<String>> map)
714  {
715    final String trimmedValue = value.getText().trim();
716    if (!trimmedValue.trim().isEmpty())
717    {
718      map.put(key, Arrays.asList(trimmedValue));
719    }
720  }
721
722  private String getDescription()
723  {
724    return description.getText().trim();
725  }
726
727  private AttributeType getAttribute()
728  {
729    return new AttributeType("",
730                             getAttributeName(),
731                             getAllNames(),
732                             getOID(),
733                             getDescription(),
734                             getSuperior(),
735                             (Syntax) syntax.getSelectedItem(),
736                             getApproximateMatchingRule(),
737                             getEqualityMatchingRule(),
738                             getOrderingMatchingRule(),
739                             getSubstringMatchingRule(),
740                             (AttributeUsage) usage.getSelectedItem(),
741                             collective.isSelected(),
742                             nonModifiable.isSelected(),
743                             obsolete.isSelected(),
744                             singleValued.isSelected(),
745                             getExtraProperties());
746  }
747}