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