001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2008-2009 Sun Microsystems, Inc.
015 * Portions Copyright 2014-2016 ForgeRock AS.
016 */
017
018package org.opends.guitools.controlpanel.ui;
019
020import static org.opends.messages.AdminToolMessages.*;
021
022import java.awt.Component;
023import java.awt.Container;
024import java.awt.GridBagConstraints;
025import java.awt.event.KeyAdapter;
026import java.awt.event.KeyEvent;
027import java.awt.event.MouseAdapter;
028import java.awt.event.MouseEvent;
029import java.util.Comparator;
030import java.util.Set;
031import java.util.SortedSet;
032import java.util.TreeSet;
033
034import javax.swing.DefaultListModel;
035import javax.swing.JLabel;
036import javax.swing.JList;
037
038import org.opends.guitools.controlpanel.event.ConfigurationChangeEvent;
039import org.opends.guitools.controlpanel.ui.components.TitlePanel;
040import org.opends.guitools.controlpanel.util.LowerCaseComparator;
041import org.opends.guitools.controlpanel.util.Utilities;
042import org.forgerock.i18n.LocalizableMessage;
043import org.forgerock.i18n.LocalizableMessageBuilder;
044import org.forgerock.opendj.ldap.schema.MatchingRule;
045import org.forgerock.opendj.ldap.schema.AttributeType;
046import org.opends.server.schema.SomeSchemaElement;
047import org.opends.server.types.ObjectClass;
048import org.opends.server.types.Schema;
049
050/**
051 * The panel that displays a standard attribute definition.
052 *
053 */
054public class StandardAttributePanel extends SchemaElementPanel
055{
056  private static final long serialVersionUID = -7922968631524763675L;
057  private TitlePanel titlePanel = new TitlePanel(LocalizableMessage.EMPTY,
058      LocalizableMessage.EMPTY);
059  private JLabel name = Utilities.createDefaultLabel();
060  private JLabel parent = Utilities.createDefaultLabel();
061  private JLabel oid = Utilities.createDefaultLabel();
062  private JLabel aliases = Utilities.createDefaultLabel();
063  private JLabel origin = Utilities.createDefaultLabel();
064  private JLabel description = Utilities.createDefaultLabel();
065  private JLabel usage = Utilities.createDefaultLabel();
066  private JLabel syntax = Utilities.createDefaultLabel();
067  private JLabel approximate = Utilities.createDefaultLabel();
068  private JLabel equality = Utilities.createDefaultLabel();
069  private JLabel ordering = Utilities.createDefaultLabel();
070  private JLabel substring = Utilities.createDefaultLabel();
071  private JLabel type = Utilities.createDefaultLabel();
072  private JList requiredBy = new JList(new DefaultListModel());
073  private JList optionalBy = new JList(new DefaultListModel());
074
075  /**
076   * Default constructor of the panel.
077   *
078   */
079  public StandardAttributePanel()
080  {
081    super();
082    createLayout();
083  }
084
085  /** {@inheritDoc} */
086  public LocalizableMessage getTitle()
087  {
088    return INFO_CTRL_PANEL_STANDARD_ATTRIBUTE_TITLE.get();
089  }
090
091  /** {@inheritDoc} */
092  public Component getPreferredFocusComponent()
093  {
094    return requiredBy;
095  }
096
097  /** {@inheritDoc} */
098  public void configurationChanged(ConfigurationChangeEvent ev)
099  {
100  }
101
102  /** {@inheritDoc} */
103  public void okClicked()
104  {
105  }
106
107  /**
108   * Creates the layout of the panel (but the contents are not populated here).
109   */
110  protected void createLayout()
111  {
112    createBasicLayout(this, new GridBagConstraints());
113    setBorder(PANEL_BORDER);
114  }
115
116  /**
117   * Creates the basic layout of the panel.
118   * @param c the container where all the components will be layed out.
119   * @param gbc the grid bag constraints.
120   */
121  protected void createBasicLayout(Container c, GridBagConstraints gbc)
122  {
123    requiredBy.setVisibleRowCount(5);
124    optionalBy.setVisibleRowCount(9);
125
126    gbc.gridy = 0;
127    gbc.gridwidth = 2;
128    addErrorPane(c, gbc);
129    gbc.gridy ++;
130
131    gbc.anchor = GridBagConstraints.WEST;
132    titlePanel.setTitle(INFO_CTRL_PANEL_ATTRIBUTE_DETAILS.get());
133    gbc.fill = GridBagConstraints.NONE;
134    gbc.insets.top = 5;
135    gbc.insets.bottom = 7;
136    c.add(titlePanel, gbc);
137
138    gbc.insets.bottom = 0;
139    gbc.insets.top = 8;
140    gbc.gridy ++;
141    gbc.gridwidth = 1;
142    gbc.fill = GridBagConstraints.HORIZONTAL;
143
144    LocalizableMessage[] labels = {
145        INFO_CTRL_PANEL_ATTRIBUTE_NAME_LABEL.get(),
146        INFO_CTRL_PANEL_ATTRIBUTE_PARENT_LABEL.get(),
147        INFO_CTRL_PANEL_ATTRIBUTE_OID_LABEL.get(),
148        INFO_CTRL_PANEL_ATTRIBUTE_ALIASES_LABEL.get(),
149        INFO_CTRL_PANEL_ATTRIBUTE_ORIGIN_LABEL.get(),
150        INFO_CTRL_PANEL_ATTRIBUTE_DESCRIPTION_LABEL.get(),
151        INFO_CTRL_PANEL_ATTRIBUTE_USAGE_LABEL.get(),
152        INFO_CTRL_PANEL_ATTRIBUTE_SYNTAX_LABEL.get(),
153        INFO_CTRL_PANEL_ATTRIBUTE_TYPE_LABEL.get(),
154        INFO_CTRL_PANEL_ATTRIBUTE_APPROXIMATE_MATCHING_RULE_LABEL.get(),
155        INFO_CTRL_PANEL_ATTRIBUTE_EQUALITY_MATCHING_RULE_LABEL.get(),
156        INFO_CTRL_PANEL_ATTRIBUTE_ORDERING_MATCHING_RULE_LABEL.get(),
157        INFO_CTRL_PANEL_ATTRIBUTE_SUBSTRING_MATCHING_RULE_LABEL.get()
158    };
159    JLabel[] values = {name, parent, oid, aliases, origin, description, usage,
160        syntax, type, approximate, equality, ordering, substring};
161
162    for (int i=0; i < labels.length; i++)
163    {
164      gbc.insets.left = 0;
165      gbc.gridx = 0;
166      JLabel l = Utilities.createPrimaryLabel(labels[i]);
167      c.add(l, gbc);
168      gbc.insets.left = 10;
169      gbc.gridx = 1;
170      c.add(values[i], gbc);
171      gbc.gridy ++;
172    }
173    labels = new LocalizableMessage[] {
174        INFO_CTRL_PANEL_REQUIRED_BY_LABEL.get(),
175        INFO_CTRL_PANEL_ALLOWED_BY_LABEL.get()
176        };
177    JList[] lists = {requiredBy, optionalBy};
178    gbc.anchor = GridBagConstraints.NORTHWEST;
179    for (int i=0; i<2; i++)
180    {
181      gbc.insets.left = 0;
182      gbc.gridx = 0;
183      JLabel l = Utilities.createPrimaryLabel(labels[i]);
184      gbc.weightx = 0.0;
185      gbc.fill = GridBagConstraints.HORIZONTAL;
186      c.add(l, gbc);
187      gbc.insets.left = 10;
188      gbc.gridx = 1;
189      if (i == 0)
190      {
191        gbc.weighty = 0.35;
192      }
193      else
194      {
195        gbc.weighty = 0.65;
196      }
197      gbc.weightx = 1.0;
198      gbc.fill = GridBagConstraints.BOTH;
199      gbc.insets.top = 10;
200      c.add(Utilities.createScrollPane(lists[i]), gbc);
201      gbc.gridy ++;
202
203      final JList list = lists[i];
204      MouseAdapter clickListener = new MouseAdapter()
205      {
206        /** {@inheritDoc} */
207        public void mouseClicked(MouseEvent ev)
208        {
209          if (ev.getClickCount() == 1)
210          {
211            objectClassSelected(list);
212          }
213        }
214      };
215      list.addMouseListener(clickListener);
216
217      KeyAdapter keyListener = new KeyAdapter()
218      {
219        /** {@inheritDoc} */
220        public void keyTyped(KeyEvent ev)
221        {
222          if (ev.getKeyChar() == KeyEvent.VK_SPACE ||
223              ev.getKeyChar() == KeyEvent.VK_ENTER)
224          {
225            objectClassSelected(list);
226          }
227        }
228      };
229      list.addKeyListener(keyListener);
230    }
231  }
232
233  /**
234   * Updates the contents of the panel with the provided attribute.
235   * @param attr the attribute.
236   * @param schema the schema.
237   */
238  public void update(AttributeType attr, Schema schema)
239  {
240    String n = attr.getNameOrOID();
241    titlePanel.setDetails(LocalizableMessage.raw(n));
242    name.setText(n);
243    AttributeType superior = attr.getSuperiorType();
244    if (superior == null)
245    {
246      n = null;
247    }
248    else
249    {
250      n = superior.getNameOrOID();
251    }
252    parent.setText(n);
253    oid.setText(attr.getOID());
254    origin.setText(StandardObjectClassPanel.getOrigin(new SomeSchemaElement(attr)).toString());
255    n = attr.getDescription();
256    if (n == null)
257    {
258      n = NOT_APPLICABLE.toString();
259    }
260    description.setText(n);
261    if (attr.getUsage() == null)
262    {
263      n = NOT_APPLICABLE.toString();
264    }
265    else
266    {
267      n = attr.getUsage().toString();
268    }
269    usage.setText(n);
270    Set<String> aliases = getAliases(attr);
271    if (!aliases.isEmpty())
272    {
273      n = Utilities.getStringFromCollection(aliases, ", ");
274    }
275    else
276    {
277      n = NOT_APPLICABLE.toString();
278    }
279    this.aliases.setText(n);
280    syntax.setText(Utilities.getSyntaxText(attr.getSyntax()));
281    JLabel[] labels = {approximate, equality, ordering, substring};
282    MatchingRule[] rules = {attr.getApproximateMatchingRule(),
283        attr.getEqualityMatchingRule(), attr.getOrderingMatchingRule(),
284        attr.getSubstringMatchingRule()
285    };
286    for (int i=0; i<labels.length; i++)
287    {
288      if (rules[i] != null)
289      {
290        labels[i].setText(Utilities.getMatchingRuleText(rules[i]));
291      }
292      else
293      {
294        labels[i].setText(NOT_APPLICABLE.toString());
295      }
296    }
297
298    type.setText(getTypeValue(attr).toString());
299
300    Comparator<String> lowerCaseComparator = new LowerCaseComparator();
301    SortedSet<String> requiredByOcs = new TreeSet<>(lowerCaseComparator);
302    for (ObjectClass oc : schema.getObjectClasses().values())
303    {
304      if (oc.getRequiredAttributeChain().contains(attr))
305      {
306        requiredByOcs.add(oc.getNameOrOID());
307      }
308    }
309
310    DefaultListModel model = (DefaultListModel)requiredBy.getModel();
311    model.clear();
312    for (String oc : requiredByOcs)
313    {
314      model.addElement(oc);
315    }
316
317    SortedSet<String> optionalByOcs = new TreeSet<>(lowerCaseComparator);
318    for (ObjectClass oc : schema.getObjectClasses().values())
319    {
320      if (oc.getOptionalAttributeChain().contains(attr))
321      {
322        optionalByOcs.add(oc.getNameOrOID());
323      }
324    }
325
326    model = (DefaultListModel)optionalBy.getModel();
327    model.clear();
328    for (String oc : optionalByOcs)
329    {
330      model.addElement(oc);
331    }
332  }
333
334  /**
335   * Returns the message describing the attribute type (operational, single
336   * valued, etc.).
337   * @param attr the attribute.
338   * @return the message describing the attribute type (operational, single
339   * valued, etc.).
340   */
341  static LocalizableMessage getTypeValue(AttributeType attr)
342  {
343    LocalizableMessageBuilder mb = new LocalizableMessageBuilder();
344    Boolean[] props = {attr.isOperational(), attr.isSingleValue(),
345        attr.isNoUserModification(), attr.isCollective(),
346        attr.isObsolete()};
347    LocalizableMessage[][] values = {
348        {INFO_CTRL_PANEL_ATTRIBUTE_OPERATIONAL_LABEL.get(), null},
349        {INFO_CTRL_PANEL_ATTRIBUTE_SINGLE_VALUED_LABEL.get(),
350          INFO_CTRL_PANEL_ATTRIBUTE_MULTI_VALUED_LABEL.get()},
351        {INFO_CTRL_PANEL_ATTRIBUTE_NON_MODIFIABLE_LABEL.get(), null},
352        {INFO_CTRL_PANEL_ATTRIBUTE_COLLECTIVE_LABEL.get(), null},
353        {INFO_CTRL_PANEL_ATTRIBUTE_OBSOLETE_LABEL.get(), null}};
354    int i = 0;
355    for (Boolean prop : props)
356    {
357      LocalizableMessage value = prop ? values[i][0] : values[i][1];
358      if (value != null)
359      {
360        if (mb.length() > 0)
361        {
362          mb.append(", ");
363        }
364        mb.append(value);
365      }
366      i++;
367    }
368    return mb.toMessage();
369  }
370}