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 2015 ForgeRock AS. 026 */ 027 028package org.opends.guitools.controlpanel.ui.components; 029 030import static org.opends.messages.AdminToolMessages.*; 031 032import java.awt.Component; 033import java.awt.Dimension; 034import java.awt.GridBagConstraints; 035import java.awt.GridBagLayout; 036import java.awt.Insets; 037import java.awt.event.ActionEvent; 038import java.awt.event.ActionListener; 039import java.awt.event.MouseAdapter; 040import java.awt.event.MouseEvent; 041 042import javax.swing.Box; 043import javax.swing.JButton; 044import javax.swing.JLabel; 045import javax.swing.JList; 046import javax.swing.JPanel; 047import javax.swing.JScrollPane; 048import javax.swing.ListSelectionModel; 049import javax.swing.event.ListDataEvent; 050import javax.swing.event.ListDataListener; 051import javax.swing.event.ListSelectionEvent; 052import javax.swing.event.ListSelectionListener; 053 054import org.opends.guitools.controlpanel.datamodel.SortableListModel; 055import org.opends.guitools.controlpanel.util.Utilities; 056 057/** 058 * This component displays two list (available list and selected list) with 059 * some buttons to move the components of one list to the other. 060 * 061 * @param <T> the type of the objects in the list. 062 */ 063public class AddRemovePanel<T> extends JPanel 064{ 065 private static final long serialVersionUID = 461800576153651284L; 066 private SortableListModel<T> availableListModel; 067 private SortableListModel<T> selectedListModel; 068 private JLabel selectedLabel; 069 private JLabel availableLabel; 070 private JButton add; 071 private JButton remove; 072 private JButton addAll; 073 private JButton removeAll; 074 private JScrollPane availableScroll; 075 private JScrollPane selectedScroll; 076 private JList availableList; 077 private JList selectedList; 078 private Class<T> theClass; 079 080 /** 081 * Mask used as display option. If the provided display options contain 082 * this mask, the panel will display the remove all button. 083 */ 084 public static final int DISPLAY_REMOVE_ALL = 0x001; 085 086 /** 087 * Mask used as display option. If the provided display options contain 088 * this mask, the panel will display the add all button. 089 */ 090 public static final int DISPLAY_ADD_ALL = 0x010; 091 092 093 /** 094 * Constructor of the default add remove panel (including 'Add All' and 095 * 'Remove All' buttons). 096 * The class is required to avoid warnings in compilation. 097 * @param theClass the class of the objects in the panel. 098 */ 099 public AddRemovePanel(Class<T> theClass) 100 { 101 this(DISPLAY_REMOVE_ALL | DISPLAY_ADD_ALL, theClass); 102 } 103 104 /** 105 * Constructor of the add remove panel allowing the user to provide some 106 * display options. 107 * The class is required to avoid warnings in compilation. 108 * @param displayOptions the display options. 109 * @param theClass the class of the objects in the panel. 110 */ 111 public AddRemovePanel(int displayOptions, Class<T> theClass) 112 { 113 super(new GridBagLayout()); 114 setOpaque(false); 115 this.theClass = theClass; 116 GridBagConstraints gbc = new GridBagConstraints(); 117 gbc.gridx = 0; 118 gbc.gridy = 0; 119 gbc.weightx = 0.0; 120 gbc.weighty = 0.0; 121 gbc.gridwidth = 1; 122 gbc.gridheight = 1; 123 gbc.fill = GridBagConstraints.HORIZONTAL; 124 gbc.anchor = GridBagConstraints.WEST; 125 126 availableLabel = Utilities.createDefaultLabel( 127 INFO_CTRL_PANEL_AVAILABLE_LABEL.get()); 128 add(availableLabel, gbc); 129 gbc.gridx = 2; 130 selectedLabel = Utilities.createDefaultLabel( 131 INFO_CTRL_PANEL_SELECTED_LABEL.get()); 132 add(selectedLabel, gbc); 133 gbc.gridy ++; 134 135 ListDataListener listDataListener = new ListDataListener() 136 { 137 /** {@inheritDoc} */ 138 public void intervalRemoved(ListDataEvent ev) 139 { 140 updateButtonEnabling(); 141 } 142 143 /** {@inheritDoc} */ 144 public void intervalAdded(ListDataEvent ev) 145 { 146 updateButtonEnabling(); 147 } 148 149 /** {@inheritDoc} */ 150 public void contentsChanged(ListDataEvent ev) 151 { 152 updateButtonEnabling(); 153 } 154 }; 155 MouseAdapter doubleClickListener = new MouseAdapter() 156 { 157 /** {@inheritDoc} */ 158 public void mouseClicked(MouseEvent e) { 159 if (isEnabled() && e.getClickCount() == 2) 160 { 161 if (e.getSource() == availableList) 162 { 163 if (availableList.getSelectedValue() != null) 164 { 165 addClicked(); 166 } 167 } 168 else if (e.getSource() == selectedList) 169 { 170 if (selectedList.getSelectedValue() != null) 171 { 172 removeClicked(); 173 } 174 } 175 } 176 } 177 }; 178 179 180 availableListModel = new SortableListModel<>(); 181 availableListModel.addListDataListener(listDataListener); 182 availableList = new JList(); 183 availableList.setModel(availableListModel); 184 availableList.setVisibleRowCount(15); 185 availableList.addMouseListener(doubleClickListener); 186 187 selectedListModel = new SortableListModel<>(); 188 selectedListModel.addListDataListener(listDataListener); 189 selectedList = new JList(); 190 selectedList.setModel(selectedListModel); 191 selectedList.setVisibleRowCount(15); 192 selectedList.addMouseListener(doubleClickListener); 193 194 gbc.weighty = 1.0; 195 gbc.weightx = 1.0; 196 gbc.gridheight = 3; 197 if ((displayOptions & DISPLAY_ADD_ALL) != 0) 198 { 199 gbc.gridheight ++; 200 } 201 if ((displayOptions & DISPLAY_REMOVE_ALL) != 0) 202 { 203 gbc.gridheight ++; 204 } 205 int listGridHeight = gbc.gridheight; 206 int listGridY = gbc.gridy; 207 gbc.gridx = 0; 208 gbc.insets.top = 5; 209 availableScroll = Utilities.createScrollPane(availableList); 210 gbc.fill = GridBagConstraints.BOTH; 211 add(availableScroll, gbc); 212 213 gbc.gridx = 1; 214 gbc.gridheight = 1; 215 gbc.weightx = 0.0; 216 gbc.weighty = 0.0; 217 gbc.fill = GridBagConstraints.HORIZONTAL; 218 add = Utilities.createButton(INFO_CTRL_PANEL_ADDREMOVE_ADD_BUTTON.get()); 219 add.setOpaque(false); 220 add.addActionListener(new ActionListener() 221 { 222 /** {@inheritDoc} */ 223 public void actionPerformed(ActionEvent ev) 224 { 225 addClicked(); 226 } 227 }); 228 gbc.insets = new Insets(5, 5, 0, 5); 229 add(add, gbc); 230 231 if ((displayOptions & DISPLAY_ADD_ALL) != 0) 232 { 233 addAll = Utilities.createButton( 234 INFO_CTRL_PANEL_ADDREMOVE_ADD_ALL_BUTTON.get()); 235 addAll.setOpaque(false); 236 addAll.addActionListener(new ActionListener() 237 { 238 /** {@inheritDoc} */ 239 public void actionPerformed(ActionEvent ev) 240 { 241 selectedListModel.addAll(availableListModel.getData()); 242 availableListModel.clear(); 243 selectedListModel.fireContentsChanged(selectedListModel, 0, 244 selectedListModel.getSize()); 245 availableListModel.fireContentsChanged(availableListModel, 0, 246 availableListModel.getSize()); 247 } 248 }); 249 gbc.gridy ++; 250 add(addAll, gbc); 251 } 252 253 remove = Utilities.createButton( 254 INFO_CTRL_PANEL_ADDREMOVE_REMOVE_BUTTON.get()); 255 remove.setOpaque(false); 256 remove.addActionListener(new ActionListener() 257 { 258 /** {@inheritDoc} */ 259 public void actionPerformed(ActionEvent ev) 260 { 261 removeClicked(); 262 } 263 }); 264 gbc.gridy ++; 265 gbc.insets.top = 10; 266 add(remove, gbc); 267 268 if ((displayOptions & DISPLAY_REMOVE_ALL) != 0) 269 { 270 removeAll = Utilities.createButton( 271 INFO_CTRL_PANEL_ADDREMOVE_REMOVE_ALL_BUTTON.get()); 272 removeAll.setOpaque(false); 273 removeAll.addActionListener(new ActionListener() 274 { 275 /** {@inheritDoc} */ 276 public void actionPerformed(ActionEvent ev) 277 { 278 availableListModel.addAll(selectedListModel.getData()); 279 selectedListModel.clear(); 280 selectedListModel.fireContentsChanged(selectedListModel, 0, 281 selectedListModel.getSize()); 282 availableListModel.fireContentsChanged(availableListModel, 0, 283 availableListModel.getSize()); 284 } 285 }); 286 gbc.gridy ++; 287 gbc.insets.top = 5; 288 add(removeAll, gbc); 289 } 290 291 292 gbc.weighty = 1.0; 293 gbc.insets = new Insets(0, 0, 0, 0); 294 gbc.gridy ++; 295 gbc.fill = GridBagConstraints.VERTICAL; 296 add(Box.createVerticalGlue(), gbc); 297 298 gbc.weightx = 1.0; 299 gbc.insets = new Insets(5, 0, 0, 0); 300 gbc.gridheight = listGridHeight; 301 gbc.gridy = listGridY; 302 gbc.gridx = 2; 303 gbc.fill = GridBagConstraints.BOTH; 304 selectedScroll = Utilities.createScrollPane(selectedList); 305 add(selectedScroll, gbc); 306 307 selectedList.getSelectionModel().setSelectionMode( 308 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 309 ListSelectionListener listener = new ListSelectionListener() 310 { 311 public void valueChanged(ListSelectionEvent ev) 312 { 313 updateButtonEnabling(); 314 } 315 }; 316 selectedList.getSelectionModel().addListSelectionListener(listener); 317 availableList.getSelectionModel().setSelectionMode( 318 ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 319 availableList.getSelectionModel().addListSelectionListener(listener); 320 321 add.setEnabled(false); 322 remove.setEnabled(false); 323 324 // Set preferred size for the scroll panes. 325 Component comp = 326 availableList.getCellRenderer().getListCellRendererComponent( 327 availableList, 328 "The cell that we want to display", 0, true, true); 329 Dimension d = new Dimension(comp.getPreferredSize().width, 330 availableScroll.getPreferredSize().height); 331 availableScroll.setPreferredSize(d); 332 selectedScroll.setPreferredSize(d); 333 } 334 335 /** 336 * Enables the state of the components in the panel. 337 * @param enable whether to enable the components in the panel or not. 338 */ 339 public void setEnabled(boolean enable) 340 { 341 super.setEnabled(enable); 342 343 selectedLabel.setEnabled(enable); 344 availableLabel.setEnabled(enable); 345 availableList.setEnabled(enable); 346 selectedList.setEnabled(enable); 347 availableScroll.setEnabled(enable); 348 selectedScroll.setEnabled(enable); 349 350 updateButtonEnabling(); 351 } 352 353 /** 354 * Returns the available label contained in the panel. 355 * @return the available label contained in the panel. 356 */ 357 public JLabel getAvailableLabel() 358 { 359 return availableLabel; 360 } 361 362 /** 363 * Returns the list of elements in the available list. 364 * @return the list of elements in the available list. 365 */ 366 public SortableListModel<T> getAvailableListModel() 367 { 368 return availableListModel; 369 } 370 371 /** 372 * Returns the selected label contained in the panel. 373 * @return the selected label contained in the panel. 374 */ 375 public JLabel getSelectedLabel() 376 { 377 return selectedLabel; 378 } 379 380 /** 381 * Returns the list of elements in the selected list. 382 * @return the list of elements in the selected list. 383 */ 384 public SortableListModel<T> getSelectedListModel() 385 { 386 return selectedListModel; 387 } 388 389 private void updateButtonEnabling() 390 { 391 int index = availableList.getSelectedIndex(); 392 add.setEnabled(index != -1 && 393 index <availableListModel.getSize() && isEnabled()); 394 index = selectedList.getSelectedIndex(); 395 remove.setEnabled(index != -1 && 396 index <selectedListModel.getSize() && isEnabled()); 397 398 if (addAll != null) 399 { 400 addAll.setEnabled(availableListModel.getSize() > 0 && isEnabled()); 401 } 402 if (removeAll != null) 403 { 404 removeAll.setEnabled(selectedListModel.getSize() > 0 && isEnabled()); 405 } 406 } 407 408 /** 409 * Returns the available list. 410 * @return the available list. 411 */ 412 public JList getAvailableList() 413 { 414 return availableList; 415 } 416 417 /** 418 * Returns the selected list. 419 * @return the selected list. 420 */ 421 public JList getSelectedList() 422 { 423 return selectedList; 424 } 425 426 private void addClicked() 427 { 428 @SuppressWarnings("deprecation") 429 Object[] selectedObjects = availableList.getSelectedValues(); 430 for (int i=0; i<selectedObjects.length; i++) 431 { 432 T value = AddRemovePanel.this.theClass.cast(selectedObjects[i]); 433 selectedListModel.add(value); 434 availableListModel.remove(value); 435 } 436 selectedListModel.fireContentsChanged(selectedListModel, 0, 437 selectedListModel.getSize()); 438 availableListModel.fireContentsChanged(availableListModel, 0, 439 availableListModel.getSize()); 440 } 441 442 private void removeClicked() 443 { 444 @SuppressWarnings("deprecation") 445 Object[] selectedObjects = selectedList.getSelectedValues(); 446 for (int i=0; i<selectedObjects.length; i++) 447 { 448 T value = AddRemovePanel.this.theClass.cast(selectedObjects[i]); 449 availableListModel.add(value); 450 selectedListModel.remove(value); 451 } 452 selectedListModel.fireContentsChanged(selectedListModel, 0, 453 selectedListModel.getSize()); 454 availableListModel.fireContentsChanged(availableListModel, 0, 455 availableListModel.getSize()); 456 } 457}