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