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