/**
   * Updates the contents of the panel with the provided object class.
   *
   * @param oc the object class.
   * @param schema the schema.
   */
  public void update(ObjectClass oc, Schema schema) {
    ignoreChangeEvents = true;

    objectClass = oc;
    if (oc == null || schema == null) {
      // Ignore: this is called to get an initial panel size.
      return;
    }
    String n = oc.getPrimaryName();
    if (n == null) {
      n = NOT_APPLICABLE.toString();
    }
    titlePanel.setDetails(LocalizableMessage.raw(n));
    name.setText(n);

    SortableListModel<AttributeType> modelRequired = attributes.getSelectedListModel1();
    SortableListModel<AttributeType> modelAvailable = attributes.getSelectedListModel2();
    SortableListModel<AttributeType> availableModel = attributes.getAvailableListModel();
    availableModel.addAll(modelRequired.getData());
    availableModel.addAll(modelAvailable.getData());
    modelRequired.clear();
    modelAvailable.clear();

    superiors.setSelectedSuperiors(oc.getSuperiorClasses());
    superiors.setObjectClassesToExclude(Collections.singleton(oc));
    if (oc.getSuperiorClasses().size() > 1) {
      lSuperior.setText(INFO_CTRL_PANEL_OBJECTCLASS_PARENTS_LABEL.get().toString());
    } else {
      lSuperior.setText(INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString());
    }

    updateAttributesWithParent(false);

    for (AttributeType attr : oc.getRequiredAttributes()) {
      availableModel.remove(attr);
      modelRequired.add(attr);
    }
    for (AttributeType attr : oc.getOptionalAttributes()) {
      availableModel.remove(attr);
      modelAvailable.add(attr);
    }
    notifyAttributesChanged();

    oid.setText(oc.getOID());
    n = oc.getDescription();
    if (n == null) {
      n = "";
    }
    description.setText(n);

    Set<String> aliases = getAliases(oc);
    lastAliases.clear();
    lastAliases.addAll(aliases);
    this.aliases.setText(Utilities.getStringFromCollection(aliases, ", "));

    String sOrigin = Utilities.getOrigin(oc);
    if (sOrigin == null) {
      sOrigin = "";
    }
    origin.setText(sOrigin);

    String sFile = getSchemaFile(oc);
    if (sFile == null) {
      sFile = "";
    }
    file.setText(sFile);

    type.setSelectedItem(oc.getObjectClassType());

    obsolete.setSelected(oc.isObsolete());

    ocName = objectClass.getNameOrOID();
    scrollListener.updateBorder();
    for (JLabel label : labels) {
      setPrimaryValid(label);
    }
    saveChanges.setEnabled(false);
    ignoreChangeEvents = false;
  }
  /** {@inheritDoc} */
  public void okClicked() {
    setPrimaryValid(lBaseDN);
    setSecondaryValid(addRemove.getSelectedLabel());

    final LinkedHashSet<Message> errors = new LinkedHashSet<Message>();

    String baseDN = getSelectedBaseDN();

    if (baseDN == null) {
      setPrimaryInvalid(lBaseDN);
      if (baseDNs.getItemCount() == 0) {
        errors.add(ERR_CTRL_PANEL_NO_BASE_DNS_DEFINED_LABEL.get());
      } else {
        errors.add(ERR_CTRL_PANEL_MUST_SELECT_BASE_DN.get());
      }
    }

    SortableListModel<AbstractIndexDescriptor> model = addRemove.getSelectedListModel();
    if (model.getSize() == 0) {
      setSecondaryInvalid(addRemove.getSelectedLabel());
      errors.add(ERR_CTRL_PANEL_MUST_SELECT_INDEX_TO_REBUILD.get());
    }

    if (errors.isEmpty()) {
      ProgressDialog progressDialog =
          new ProgressDialog(
              Utilities.createFrame(), Utilities.getParentDialog(this), getTitle(), getInfo());
      HashSet<String> baseDNs = new HashSet<String>();
      baseDNs.add(getSelectedBaseDN());
      RebuildIndexTask newTask =
          new RebuildIndexTask(
              getInfo(), progressDialog, baseDNs, addRemove.getSelectedListModel().getData());
      for (Task task : getInfo().getTasks()) {
        task.canLaunch(newTask, errors);
      }
      boolean confirmed = true;

      if ((errors.isEmpty()) && isServerRunning()) {
        String backendName = newTask.getBackends().iterator().next();
        confirmed =
            displayConfirmationDialog(
                INFO_CTRL_PANEL_CONFIRMATION_REQUIRED_SUMMARY.get(),
                INFO_CTRL_PANEL_CONFIRM_REBUILD_INDEX_DETAILS.get(backendName));
      }
      if ((errors.isEmpty()) && confirmed) {
        launchOperation(
            newTask,
            INFO_CTRL_PANEL_REBUILDING_INDEXES_SUMMARY.get(baseDN),
            INFO_CTRL_PANEL_REBUILDING_INDEXES_SUCCESSFUL_SUMMARY.get(),
            INFO_CTRL_PANEL_REBUILDING_INDEXES_SUCCESSFUL_DETAILS.get(),
            ERR_CTRL_PANEL_REBUILDING_INDEXES_ERROR_SUMMARY.get(),
            null,
            ERR_CTRL_PANEL_REBUILDING_INDEXES_ERROR_DETAILS,
            progressDialog);
        progressDialog.setVisible(true);
        Utilities.getParentDialog(this).setVisible(false);
      }
    }
    if (errors.size() > 0) {
      displayErrorDialog(errors);
    }
  }
  /**
   * Creates the basic layout of the panel.
   *
   * @param c the container where all the components will be layed out.
   * @param gbc the grid bag constraints.
   */
  protected void createBasicLayout(Container c, GridBagConstraints gbc) {
    SuperiorObjectClassesChangedListener listener =
        new SuperiorObjectClassesChangedListener() {
          /** {@inheritDoc} */
          @Override
          public void parentObjectClassesChanged(SuperiorObjectClassesChangedEvent ev) {
            if (ignoreChangeEvents) {
              return;
            }
            updateAttributesWithParent(true);
            checkEnableSaveChanges();
            if (ev.getNewObjectClasses().size() > 1) {
              lSuperior.setText(INFO_CTRL_PANEL_OBJECTCLASS_PARENTS_LABEL.get().toString());
            } else {
              lSuperior.setText(INFO_CTRL_PANEL_OBJECTCLASS_PARENT_LABEL.get().toString());
            }
          }
        };
    superiors.addParentObjectClassesChangedListener(listener);

    DefaultComboBoxModel model = new DefaultComboBoxModel();
    for (ObjectClassType t : ObjectClassType.values()) {
      model.addElement(t);
    }
    type.setModel(model);
    type.setSelectedItem(ObjectClassType.STRUCTURAL);
    SchemaElementComboBoxCellRenderer renderer = new SchemaElementComboBoxCellRenderer(type);
    type.setRenderer(renderer);

    attributes = new DoubleAddRemovePanel<>(0, AttributeType.class);
    Comparator<AttributeType> comparator =
        new Comparator<AttributeType>() {
          /** {@inheritDoc} */
          @Override
          public int compare(AttributeType attr1, AttributeType attr2) {
            return attr1.getNameOrOID().toLowerCase().compareTo(attr2.getNameOrOID().toLowerCase());
          }
        };
    attributes.getAvailableListModel().setComparator(comparator);
    attributes.getSelectedListModel1().setComparator(comparator);
    attributes.getSelectedListModel2().setComparator(comparator);

    gbc.gridy = 0;
    gbc.gridwidth = 2;
    addErrorPane(c, gbc);
    gbc.gridy++;

    gbc.anchor = GridBagConstraints.WEST;
    titlePanel.setTitle(INFO_CTRL_PANEL_OBJECTCLASS_DETAILS.get());
    gbc.fill = GridBagConstraints.NONE;
    gbc.insets.top = 5;
    gbc.insets.bottom = 7;
    c.add(titlePanel, gbc);

    gbc.insets.bottom = 0;
    gbc.insets.top = 8;
    gbc.gridy++;
    gbc.gridwidth = 1;
    gbc.fill = GridBagConstraints.HORIZONTAL;

    Component[] basicComps = {name, oid, description, superiors};
    JLabel[] basicLabels = {lName, lOID, lDescription, lSuperior};
    JLabel[] basicInlineHelp = new JLabel[] {null, null, null, null};
    add(basicLabels, basicComps, basicInlineHelp, c, gbc);

    gbc.gridx = 0;
    gbc.weightx = 0.0;
    gbc.insets.left = 0;
    gbc.fill = GridBagConstraints.HORIZONTAL;
    gbc.anchor = GridBagConstraints.NORTHWEST;
    c.add(lAttributes, gbc);

    gbc.gridx++;
    gbc.fill = GridBagConstraints.BOTH;
    gbc.weightx = 1.0;
    gbc.weighty = 1.0;
    gbc.insets.left = 10;
    c.add(attributes, gbc);
    attributes
        .getAvailableLabel()
        .setText(INFO_CTRL_PANEL_ADDREMOVE_AVAILABLE_ATTRIBUTES.get().toString());
    attributes
        .getSelectedLabel1()
        .setText(INFO_CTRL_PANEL_ADDREMOVE_REQUIRED_ATTRIBUTES.get().toString());
    attributes
        .getSelectedLabel2()
        .setText(INFO_CTRL_PANEL_ADDREMOVE_OPTIONAL_ATTRIBUTES.get().toString());
    AttributeTypeCellRenderer listRenderer = new AttributeTypeCellRenderer();
    attributes.getAvailableList().setCellRenderer(listRenderer);
    attributes.getSelectedList1().setCellRenderer(listRenderer);
    attributes.getSelectedList2().setCellRenderer(listRenderer);

    gbc.gridy++;
    gbc.weighty = 0.0;
    gbc.insets.top = 3;
    JLabel explanation =
        Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_INHERITED_ATTRIBUTES_HELP.get());
    gbc.insets.top = 3;
    c.add(explanation, gbc);

    final BasicExpander expander = new BasicExpander(INFO_CTRL_PANEL_EXTRA_OPTIONS_EXPANDER.get());

    obsolete.setText("Obsolete");

    Component[] comps = {aliases, origin, file, type, obsolete};
    JLabel[] labels = {lAliases, lOrigin, lFile, lType, null};
    JLabel[] inlineHelps = {
      Utilities.createInlineHelpLabel(INFO_CTRL_PANEL_SEPARATED_WITH_COMMAS_HELP.get()),
      null,
      Utilities.createInlineHelpLabel(
          INFO_CTRL_PANEL_SCHEMA_FILE_OBJECTCLASS_HELP.get(File.separator)),
      null,
      null
    };
    gbc.gridwidth = 2;
    gbc.gridx = 0;
    gbc.weighty = 0.0;
    gbc.insets.left = 0;
    gbc.gridy++;
    c.add(expander, gbc);
    final JPanel p = new JPanel(new GridBagLayout());
    gbc.insets.left = 15;
    gbc.gridy++;
    c.add(p, gbc);
    gbc.gridy++;
    p.setOpaque(false);

    GridBagConstraints gbc1 = new GridBagConstraints();
    gbc1.fill = GridBagConstraints.HORIZONTAL;
    gbc1.gridy = 0;

    add(labels, comps, inlineHelps, p, gbc1);
    ChangeListener changeListener =
        new ChangeListener() {
          /** {@inheritDoc} */
          @Override
          public void stateChanged(ChangeEvent e) {
            p.setVisible(expander.isSelected());
          }
        };
    expander.addChangeListener(changeListener);
    expander.setSelected(false);
    changeListener.stateChanged(null);

    DocumentListener docListener =
        new DocumentListener() {
          /** {@inheritDoc} */
          @Override
          public void insertUpdate(DocumentEvent ev) {
            checkEnableSaveChanges();
          }

          /** {@inheritDoc} */
          @Override
          public void removeUpdate(DocumentEvent ev) {
            checkEnableSaveChanges();
          }

          /** {@inheritDoc} */
          @Override
          public void changedUpdate(DocumentEvent arg0) {
            checkEnableSaveChanges();
          }
        };
    JTextField[] tfs = {name, description, oid, aliases, origin, file};
    for (JTextField tf : tfs) {
      tf.getDocument().addDocumentListener(docListener);
    }

    ActionListener actionListener =
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent ev) {
            checkEnableSaveChanges();
          }
        };

    type.addActionListener(actionListener);

    ListDataListener dataListener =
        new ListDataListener() {
          /** {@inheritDoc} */
          @Override
          public void contentsChanged(ListDataEvent e) {
            checkEnableSaveChanges();
          }
          /** {@inheritDoc} */
          @Override
          public void intervalAdded(ListDataEvent e) {
            checkEnableSaveChanges();
          }
          /** {@inheritDoc} */
          @Override
          public void intervalRemoved(ListDataEvent e) {
            checkEnableSaveChanges();
          }
        };
    SortableListModel<AttributeType> list1 = attributes.getSelectedListModel1();
    SortableListModel<AttributeType> list2 = attributes.getSelectedListModel2();
    list1.addListDataListener(dataListener);
    list2.addListDataListener(dataListener);

    obsolete.addActionListener(actionListener);
  }