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