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 2010 Sun Microsystems, Inc. 025 * Portions Copyright 2015 ForgeRock AS. 026 */ 027package org.opends.guitools.controlpanel.ui.components; 028 029import static org.opends.messages.AdminToolMessages.*; 030 031import java.awt.CardLayout; 032import java.awt.GridBagConstraints; 033import java.awt.GridBagLayout; 034import java.awt.event.ActionEvent; 035import java.awt.event.ActionListener; 036import java.awt.event.ItemEvent; 037import java.awt.event.ItemListener; 038import java.util.ArrayList; 039import java.util.Collections; 040import java.util.HashMap; 041import java.util.HashSet; 042import java.util.Set; 043import java.util.SortedSet; 044import java.util.TreeSet; 045 046import javax.swing.Box; 047import javax.swing.DefaultComboBoxModel; 048import javax.swing.JButton; 049import javax.swing.JComboBox; 050import javax.swing.JLabel; 051import javax.swing.JPanel; 052 053import org.opends.guitools.controlpanel.event.SuperiorObjectClassesChangedEvent; 054import org.opends.guitools.controlpanel.event. 055 SuperiorObjectClassesChangedListener; 056import org.opends.guitools.controlpanel.ui.GenericDialog; 057import org.opends.guitools.controlpanel.ui.SelectObjectClassesPanel; 058import org.opends.guitools.controlpanel.ui.renderer. 059 SchemaElementComboBoxCellRenderer; 060import org.opends.guitools.controlpanel.util.LowerCaseComparator; 061import org.opends.guitools.controlpanel.util.Utilities; 062import org.opends.server.types.ObjectClass; 063import org.opends.server.types.Schema; 064 065/** 066 * A panel that can be used to select one (or several) object classes. 067 */ 068public class SuperiorObjectClassesEditor extends JPanel 069{ 070 private static final long serialVersionUID = 123123973933568L; 071 072 private Set<ObjectClass> toExclude = new HashSet<>(); 073 private JComboBox singleSuperior = Utilities.createComboBox(); 074 private JLabel multipleSuperiors = Utilities.createDefaultLabel(); 075 private JButton bSpecifyMultiple = Utilities.createButton( 076 INFO_CTRL_PANEL_SPECIFY_MULTIPLE_SUPERIORS_LABEL.get()); 077 private JButton bUpdateMultiple = Utilities.createButton( 078 INFO_CTRL_PANEL_UPDATE_MULTIPLE_SUPERIORS_LABEL.get()); 079 080 private SelectObjectClassesPanel superiorsPanel; 081 private GenericDialog superiorsDialog; 082 083 private String MULTIPLE = "Multiple"; 084 private String SINGLE = "Single"; 085 086 private CardLayout cardLayout = new CardLayout(); 087 088 private boolean isMultiple; 089 090 private Set<ObjectClass> selectedMultipleSuperiors = new HashSet<>(); 091 private Set<SuperiorObjectClassesChangedListener> listeners = new HashSet<>(); 092 093 private Schema schema; 094 095 /** 096 * Default constructor for this panel. 097 */ 098 public SuperiorObjectClassesEditor() 099 { 100 super(new CardLayout()); 101 cardLayout = (CardLayout)getLayout(); 102 setOpaque(false); 103 createLayout(); 104 } 105 106 /** 107 * Constructor for this panel. 108 * @param schema a non {@code null} schema object. 109 */ 110 public SuperiorObjectClassesEditor(Schema schema) 111 { 112 this(); 113 updateWithSchema(schema); 114 } 115 116 /** 117 * Creates the layout of this panel. 118 */ 119 private void createLayout() 120 { 121 bSpecifyMultiple.setToolTipText( 122 INFO_CTRL_PANEL_SPECIFY_MULTIPLE_SUPERIORS_TOOLTIP.get().toString()); 123 bSpecifyMultiple.addActionListener(new ActionListener() 124 { 125 public void actionPerformed(ActionEvent ev) 126 { 127 specifyMultipleClicked(); 128 } 129 }); 130 bUpdateMultiple.setToolTipText( 131 INFO_CTRL_PANEL_UPDATE_MULTIPLE_SUPERIORS_TOOLTIP.get().toString()); 132 bUpdateMultiple.addActionListener(new ActionListener() 133 { 134 public void actionPerformed(ActionEvent ev) 135 { 136 updateMultipleClicked(); 137 } 138 }); 139 SchemaElementComboBoxCellRenderer renderer = new 140 SchemaElementComboBoxCellRenderer(singleSuperior); 141 DefaultComboBoxModel model = new DefaultComboBoxModel(); 142 singleSuperior.setModel(model); 143 singleSuperior.setRenderer(renderer); 144 ItemListener itemListener = new ItemListener() 145 { 146 /** {@inheritDoc} */ 147 public void itemStateChanged(ItemEvent ev) 148 { 149 notifyListeners(); 150 } 151 }; 152 singleSuperior.addItemListener(itemListener); 153 154 JPanel singlePanel = new JPanel(new GridBagLayout()); 155 singlePanel.setOpaque(false); 156 JPanel multiplePanel = new JPanel(new GridBagLayout()); 157 multiplePanel.setOpaque(false); 158 GridBagConstraints gbc = new GridBagConstraints(); 159 gbc.gridx = 0; 160 gbc.gridy = 0; 161 gbc.fill = GridBagConstraints.HORIZONTAL; 162 gbc.anchor = GridBagConstraints.WEST; 163 singlePanel.add(singleSuperior, gbc); 164 multiplePanel.add(multipleSuperiors, gbc); 165 166 gbc.gridx ++; 167 gbc.insets.left = 5; 168 gbc.weightx = 0.0; 169 gbc.fill = GridBagConstraints.NONE; 170 171 singlePanel.add(bSpecifyMultiple, gbc); 172 multiplePanel.add(bUpdateMultiple, gbc); 173 174 gbc.gridx ++; 175 gbc.insets.left = 0; 176 gbc.fill = GridBagConstraints.HORIZONTAL; 177 gbc.weightx = 0.1; 178 singlePanel.add(Box.createHorizontalGlue(), gbc); 179 multiplePanel.add(Box.createHorizontalGlue(), gbc); 180 181 add(singlePanel, SINGLE); 182 add(multiplePanel, MULTIPLE); 183 184 Set<ObjectClass> empty = Collections.emptySet(); 185 setSelectedSuperiors(empty); 186 } 187 188 /** 189 * Sets the list of object classes that this panel should not display 190 * (mainly used to not display the object class for which we are editing 191 * the superior object classes). 192 * @param toExclude the list of object classes to exclude. 193 */ 194 public void setObjectClassesToExclude(Set<ObjectClass> toExclude) 195 { 196 this.toExclude.clear(); 197 this.toExclude.addAll(toExclude); 198 updateWithSchema(schema); 199 if (superiorsPanel != null) 200 { 201 superiorsPanel.setObjectClassesToExclude(toExclude); 202 } 203 } 204 205 /** 206 * Returns the list of object classes that this panel will not display. 207 * @return the list of object classes that this panel will not display. 208 */ 209 public Set<ObjectClass> getObjectClassToExclude() 210 { 211 return Collections.unmodifiableSet(toExclude); 212 } 213 214 /** 215 * Sets the list of superior object classes that must be displayed by 216 * this panel. 217 * @param objectClasses the list of superior object classes to be displayed. 218 */ 219 public void setSelectedSuperiors(Set<ObjectClass> objectClasses) 220 { 221 isMultiple = objectClasses.size() > 1; 222 if (isMultiple) 223 { 224 cardLayout.show(this, MULTIPLE); 225 selectedMultipleSuperiors.clear(); 226 selectedMultipleSuperiors.addAll(objectClasses); 227 updateMultipleSuperiorsLabel(selectedMultipleSuperiors); 228 } 229 else 230 { 231 if (objectClasses.size() == 1) 232 { 233 singleSuperior.setSelectedItem(objectClasses.iterator().next()); 234 } 235 cardLayout.show(this, SINGLE); 236 } 237 } 238 239 private void updateMultipleSuperiorsLabel( 240 Set<ObjectClass> superiors) 241 { 242 SortedSet<String> orderedOcs = new TreeSet<>(new LowerCaseComparator()); 243 for (ObjectClass oc : superiors) 244 { 245 orderedOcs.add(oc.getNameOrOID()); 246 } 247 String s = Utilities.getStringFromCollection(orderedOcs, ", "); 248 multipleSuperiors.setText(s); 249 } 250 251 /** 252 * Returns the list of superior object classes displayed by this panel. 253 * @return the list of superior object classes displayed by this panel. 254 */ 255 public Set<ObjectClass> getSelectedSuperiors() 256 { 257 if (isMultiple) 258 { 259 return Collections.unmodifiableSet(selectedMultipleSuperiors); 260 } 261 262 ObjectClass oc = (ObjectClass)singleSuperior.getSelectedItem(); 263 if (oc != null) 264 { 265 return Collections.singleton(oc); 266 } 267 return Collections.emptySet(); 268 } 269 270 /** 271 * Sets the schema to be used by this panel. This method assumes that it 272 * is being called from the event thread. 273 * @param schema the schema to be used by this panel. 274 */ 275 public void setSchema(Schema schema) 276 { 277 updateWithSchema(schema); 278 if (superiorsPanel != null) 279 { 280 superiorsPanel.setSchema(schema); 281 } 282 } 283 284 private void updateWithSchema(Schema schema) 285 { 286 HashMap<String, ObjectClass> objectClassNameMap = new HashMap<>(); 287 for (String key : schema.getObjectClasses().keySet()) 288 { 289 ObjectClass oc = schema.getObjectClass(key); 290 if (!toExclude.contains(oc)) 291 { 292 objectClassNameMap.put(oc.getNameOrOID(), oc); 293 } 294 } 295 SortedSet<String> orderedKeys = new TreeSet<>(new LowerCaseComparator()); 296 orderedKeys.addAll(objectClassNameMap.keySet()); 297 ArrayList<Object> newParents = new ArrayList<>(); 298 for (String key : orderedKeys) 299 { 300 newParents.add(objectClassNameMap.get(key)); 301 } 302 Utilities.updateComboBoxModel(newParents, 303 (DefaultComboBoxModel)singleSuperior.getModel()); 304 305 if (this.schema == null) 306 { 307 // Select the values. 308 ObjectClass topClass = schema.getObjectClass("top"); 309 singleSuperior.setSelectedItem(topClass); 310 } 311 this.schema = schema; 312 } 313 314 /** 315 * Adds a listener that will receive events when a change is made in the 316 * displayed superior object classes. 317 * @param listener the listener to be added. 318 */ 319 public void addParentObjectClassesChangedListener( 320 SuperiorObjectClassesChangedListener listener) 321 { 322 listeners.add(listener); 323 } 324 325 /** 326 * Removes the provided listener. 327 * @param listener the listener to be removed. 328 */ 329 public void removeParentObjectClassesChangedListener( 330 SuperiorObjectClassesChangedListener listener) 331 { 332 listeners.remove(listener); 333 } 334 335 private void specifyMultipleClicked() 336 { 337 updateMultipleClicked(); 338 } 339 340 private void updateMultipleClicked() 341 { 342 Set<ObjectClass> selectedObjectClasses = getSelectedSuperiors(); 343 344 // Display the panel with all the stuff. 345 if (superiorsPanel == null) 346 { 347 superiorsPanel = new SelectObjectClassesPanel(); 348 superiorsPanel.setSchema(schema); 349 if (!toExclude.isEmpty()) 350 { 351 superiorsPanel.setObjectClassesToExclude(toExclude); 352 } 353 superiorsDialog = new GenericDialog(Utilities.getFrame(this), 354 superiorsPanel); 355 Utilities.centerGoldenMean(superiorsDialog, 356 Utilities.getParentDialog(this)); 357 superiorsDialog.setModal(true); 358 superiorsDialog.pack(); 359 } 360 superiorsPanel.setSelectedObjectClasses(selectedObjectClasses); 361 superiorsDialog.setVisible(true); 362 if (!superiorsPanel.isCanceled()) 363 { 364 setSelectedSuperiors(superiorsPanel.getSelectedObjectClasses()); 365 notifyListeners(); 366 } 367 } 368 369 private void notifyListeners() 370 { 371 SuperiorObjectClassesChangedEvent ev = 372 new SuperiorObjectClassesChangedEvent(this, getSelectedSuperiors()); 373 for (SuperiorObjectClassesChangedListener listener : listeners) 374 { 375 listener.parentObjectClassesChanged(ev); 376 } 377 } 378}