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