001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.ui.util; 029 030import java.util.IdentityHashMap; 031import java.util.List; 032 033import com.google.common.collect.Lists; 034import com.google.common.collect.Maps; 035import com.vaadin.v7.data.Property.ValueChangeEvent; 036import com.vaadin.v7.data.Property.ValueChangeListener; 037import com.vaadin.v7.ui.CheckBox; 038import com.vaadin.ui.Component; 039 040/** 041 * Ensures that among a set of check boxes, at most one of them is checked, without imposing constraints on the location of the checkboxes 042 * in the UI. 043 */ 044public class CmsLogicalCheckboxGroup { 045 046 /** 047 * Listener interface.<p> 048 */ 049 public static interface I_ChangeListener { 050 051 /** 052 * Gets called when the selected check box changes.<p> 053 * 054 * @param box the selected check box, or null if deselected 055 */ 056 void onSelect(CheckBox box); 057 } 058 059 /** The check boxes of this group. */ 060 private List<CheckBox> m_checkboxes = Lists.newArrayList(); 061 062 /** The change listener. */ 063 private I_ChangeListener m_listener; 064 065 /** Value change listeners for the check boxes. */ 066 private IdentityHashMap<Component, ValueChangeListener> m_listeners = Maps.newIdentityHashMap(); 067 068 /** True if we are currently processing an event, used to prevent infinite recursion. */ 069 private boolean m_runningEvent; 070 071 /** The currently selected check box, or null if none is selected. */ 072 private CheckBox m_selected; 073 074 /** 075 * Adds a check box to the group.<p> 076 * 077 * @param checkBox the check box to add 078 */ 079 public void add(final CheckBox checkBox) { 080 081 checkBox.setValue(Boolean.FALSE); 082 m_checkboxes.add(checkBox); 083 ValueChangeListener listener = new ValueChangeListener() { 084 085 private static final long serialVersionUID = 1L; 086 087 @SuppressWarnings("synthetic-access") 088 public void valueChange(ValueChangeEvent event) { 089 090 if (m_runningEvent) { 091 return; 092 } else { 093 try { 094 m_runningEvent = true; 095 if (((Boolean)event.getProperty().getValue()).booleanValue()) { 096 if ((m_selected != null) && (m_selected != checkBox)) { 097 m_selected.setValue(Boolean.FALSE); 098 } 099 setActiveCheckBox(checkBox); 100 } else { 101 setActiveCheckBox(null); 102 m_selected = null; 103 } 104 105 // TODO Auto-generated method stub 106 } finally { 107 m_runningEvent = false; 108 109 } 110 } 111 112 } 113 }; 114 checkBox.addValueChangeListener(listener); 115 m_listeners.put(checkBox, listener); 116 } 117 118 /** 119 * Gets the currently selected check box.<p> 120 * 121 * @return the check box 122 */ 123 public CheckBox getSelected() { 124 125 return m_selected; 126 } 127 128 /** 129 * Removes a check box from the group.<p> 130 * 131 * @param checkBox the check box 132 */ 133 public void remove(CheckBox checkBox) { 134 135 m_checkboxes.remove(checkBox); 136 if (m_selected == checkBox) { 137 m_selected = null; 138 } 139 ValueChangeListener listener = m_listeners.get(checkBox); 140 if (listener != null) { 141 checkBox.removeValueChangeListener(m_listeners.get(checkBox)); 142 } 143 } 144 145 /** 146 * Sets the change listener.<p> 147 * 148 * @param listener the change listener 149 */ 150 public void setChangeListener(I_ChangeListener listener) { 151 152 m_listener = listener; 153 } 154 155 /** 156 * Sets the active check box.<p> 157 * 158 * @param box the active check box 159 */ 160 protected void setActiveCheckBox(CheckBox box) { 161 162 m_selected = box; 163 if (m_listener != null) { 164 m_listener.onSelect(box); 165 } 166 } 167 168}