001/* Checkbox.java -- An AWT checkbox widget 002 Copyright (C) 1999, 2000, 2001, 2002, 2005, 2006 003 Free Software Foundation, Inc. 004 005This file is part of GNU Classpath. 006 007GNU Classpath is free software; you can redistribute it and/or modify 008it under the terms of the GNU General Public License as published by 009the Free Software Foundation; either version 2, or (at your option) 010any later version. 011 012GNU Classpath is distributed in the hope that it will be useful, but 013WITHOUT ANY WARRANTY; without even the implied warranty of 014MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015General Public License for more details. 016 017You should have received a copy of the GNU General Public License 018along with GNU Classpath; see the file COPYING. If not, write to the 019Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02002110-1301 USA. 021 022Linking this library statically or dynamically with other modules is 023making a combined work based on this library. Thus, the terms and 024conditions of the GNU General Public License cover the whole 025combination. 026 027As a special exception, the copyright holders of this library give you 028permission to link this library with independent modules to produce an 029executable, regardless of the license terms of these independent 030modules, and to copy and distribute the resulting executable under 031terms of your choice, provided that you also meet, for each linked 032independent module, the terms and conditions of the license of that 033module. An independent module is a module which is not derived from 034or based on this library. If you modify this library, you may extend 035this exception to your version of the library, but you are not 036obligated to do so. If you do not wish to do so, delete this 037exception statement from your version. */ 038 039 040package java.awt; 041 042import java.awt.event.ItemEvent; 043import java.awt.event.ItemListener; 044import java.awt.peer.CheckboxPeer; 045import java.io.Serializable; 046 047import javax.accessibility.Accessible; 048import javax.accessibility.AccessibleAction; 049import javax.accessibility.AccessibleContext; 050import javax.accessibility.AccessibleRole; 051import javax.accessibility.AccessibleState; 052import javax.accessibility.AccessibleStateSet; 053import javax.accessibility.AccessibleValue; 054 055/** 056 * This class implements a component which has an on/off state. Two 057 * or more Checkboxes can be grouped by a CheckboxGroup. 058 * 059 * @author Aaron M. Renn (arenn@urbanophile.com) 060 * @author Tom Tromey (tromey@redhat.com) 061 */ 062public class Checkbox extends Component 063 implements ItemSelectable, Accessible, Serializable 064{ 065 066// FIXME: Need readObject/writeObject for this. 067 068/* 069 * Static Variables 070 */ 071 072// Serialization Constant 073private static final long serialVersionUID = 7270714317450821763L; 074 075/*************************************************************************/ 076 077/* 078 * Instance Variables 079 */ 080 081/** 082 * @serial The checkbox group for this checkbox. 083 */ 084private CheckboxGroup group; 085 086/** 087 * @serial The label on this checkbox. 088 */ 089private String label; 090 091/** 092 * @serial The state of this checkbox. 093 * This is package-private to avoid an accessor method. 094 */ 095boolean state; 096 097// The list of listeners for this object. 098private transient ItemListener item_listeners; 099 100 /* 101 * The number used to generate the name returned by getName. 102 */ 103 private static transient long next_checkbox_number; 104 105/** 106 * This class provides accessibility support for the 107 * checkbox. 108 * 109 * @author Jerry Quinn (jlquinn@optonline.net) 110 * @author Andrew John Hughes (gnu_andrew@member.fsf.org) 111 */ 112protected class AccessibleAWTCheckbox 113 extends AccessibleAWTComponent 114 implements ItemListener, AccessibleAction, AccessibleValue 115{ 116 /** 117 * Serialization constant to match JDK 1.5 118 */ 119 private static final long serialVersionUID = 7881579233144754107L; 120 121 /** 122 * Default constructor which simply calls the 123 * super class for generic component accessibility 124 * handling. 125 */ 126 public AccessibleAWTCheckbox() 127 { 128 super(); 129 } 130 131 /** 132 * Captures changes to the state of the checkbox and 133 * fires appropriate accessible property change events. 134 * 135 * @param event the event fired. 136 * @see java.awt.event.ItemListener#itemStateChanged(java.awt.event.ItemEvent) 137 */ 138 public void itemStateChanged(ItemEvent event) 139 { 140 firePropertyChange(ACCESSIBLE_STATE_PROPERTY, 141 state ? null : AccessibleState.CHECKED, 142 state ? AccessibleState.CHECKED : null); 143 } 144 145 /** 146 * Returns an implementation of the <code>AccessibleAction</code> 147 * interface for this accessible object. In this case, the 148 * current instance is simply returned (with a more appropriate 149 * type), as it also implements the accessible action as well as 150 * the context. 151 * 152 * @return the accessible action associated with this context. 153 * @see javax.accessibility.AccessibleAction 154 */ 155 public AccessibleAction getAccessibleAction() 156 { 157 return this; 158 } 159 160 /** 161 * Returns an implementation of the <code>AccessibleValue</code> 162 * interface for this accessible object. In this case, the 163 * current instance is simply returned (with a more appropriate 164 * type), as it also implements the accessible value as well as 165 * the context. 166 * 167 * @return the accessible value associated with this context. 168 * @see javax.accessibility.AccessibleValue 169 */ 170 public AccessibleValue getAccessibleValue() 171 { 172 return this; 173 } 174 175 /* 176 * The following methods are implemented in the JDK (up to 177 * 1.5) as stubs. We do likewise here. 178 */ 179 180 /** 181 * Returns the number of actions associated with this accessible 182 * object. This default implementation returns 0. 183 * 184 * @return the number of accessible actions available. 185 * @see javax.accessibility.AccessibleAction#getAccessibleActionCount() 186 */ 187 public int getAccessibleActionCount() 188 { 189 // 1.4.1 and 1.5 do this 190 return 0; 191 } 192 193 /** 194 * Returns a description of the action with the supplied id. 195 * This default implementation always returns null. 196 * 197 * @param i the id of the action whose description should be 198 * retrieved. 199 * @return a <code>String</code> describing the action. 200 * @see javax.accessibility.AccessibleAction#getAccessibleActionDescription(int) 201 */ 202 public String getAccessibleActionDescription(int i) 203 { 204 // 1.5 does this 205 return null; 206 } 207 208 /** 209 * Executes the action with the specified id. This 210 * default implementation simply returns false. 211 * 212 * @param i the id of the action to perform. 213 * @return true if the action was performed. 214 * @see javax.accessibility.AccessibleAction#doAccessibleAction(int) 215 */ 216 public boolean doAccessibleAction(int i) 217 { 218 // 1.5 does this 219 return false; 220 } 221 222 /** 223 * Returns the current value of this accessible object. 224 * If no value has been set, null is returned. This 225 * default implementation always returns null, regardless. 226 * 227 * @return the numeric value of this object, or null if 228 * no value has been set. 229 * @see javax.accessibility.AccessibleValue#getCurrentAccessibleValue() 230 */ 231 public Number getCurrentAccessibleValue() 232 { 233 // 1.5 does this 234 return null; 235 } 236 237 /** 238 * Sets the current value of this accessible object 239 * to that supplied. In this default implementation, 240 * the value is never set and the method always returns 241 * false. 242 * 243 * @param number the new accessible value. 244 * @return true if the value was set. 245 * @see javax.accessibility.AccessibleValue#setCurrentAccessibleValue(java.lang.Number) 246 */ 247 public boolean setCurrentAccessibleValue(Number number) 248 { 249 // 1.5 does this 250 return false; 251 } 252 253 /** 254 * Returns the minimum acceptable accessible value used 255 * by this object, or null if no minimum value exists. 256 * This default implementation always returns null. 257 * 258 * @return the minimum acceptable accessible value, or null 259 * if there is no minimum. 260 * @see javax.accessibility.AccessibleValue#getMinimumAccessibleValue() 261 */ 262 public Number getMinimumAccessibleValue() 263 { 264 return null; 265 } 266 267 /** 268 * Returns the maximum acceptable accessible value used 269 * by this object, or null if no maximum value exists. 270 * This default implementation always returns null. 271 * 272 * @return the maximum acceptable accessible value, or null 273 * if there is no maximum. 274 * @see javax.accessibility.AccessibleValue#getMaximumAccessibleValue() 275 */ 276 public Number getMaximumAccessibleValue() 277 { 278 return null; 279 } 280 281 /** 282 * Returns the role of this accessible object. 283 * 284 * @return the instance of <code>AccessibleRole</code>, 285 * which describes this object. 286 * @see javax.accessibility.AccessibleRole 287 */ 288 public AccessibleRole getAccessibleRole() 289 { 290 return AccessibleRole.CHECK_BOX; 291 } 292 293 /** 294 * Returns the state set of this accessible object. 295 * 296 * @return a set of <code>AccessibleState</code>s 297 * which represent the current state of the 298 * accessible object. 299 * @see javax.accessibility.AccessibleState 300 * @see javax.accessibility.AccessibleStateSet 301 */ 302 public AccessibleStateSet getAccessibleStateSet() 303 { 304 AccessibleStateSet set = super.getAccessibleStateSet(); 305 if (state) 306 set.add(AccessibleState.CHECKED); 307 return set; 308 } 309 310} 311 312/*************************************************************************/ 313 314/* 315 * Constructors 316 */ 317 318/** 319 * Initializes a new instance of <code>Checkbox</code> with no label, 320 * an initial state of off, and that is not part of any checkbox group. 321 */ 322public 323Checkbox() 324{ 325 this("", false, null); 326} 327 328/*************************************************************************/ 329 330/** 331 * Initializes a new instance of <code>Checkbox</code> with the specified 332 * label, an initial state of off, and that is not part of any checkbox 333 * group. 334 * 335 * @param label The label for this checkbox. 336 */ 337public 338Checkbox(String label) 339{ 340 this(label, false, null); 341} 342 343/*************************************************************************/ 344 345/** 346 * Initializes a new instance of <code>Checkbox</code> with the specified 347 * label and initial state, and that is not part of any checkbox 348 * group. 349 * 350 * @param label The label for this checkbox. 351 * @param state The initial state of the checkbox, <code>true</code> for 352 * on, <code>false</code> for off. 353 */ 354public 355Checkbox(String label, boolean state) 356{ 357 this(label, state, null); 358} 359 360/*************************************************************************/ 361 362/** 363 * Initializes a new instance of <code>Checkbox</code> with the specified 364 * label, initial state, and checkbox group. 365 * 366 * @param label The label for this checkbox. 367 * @param group The checkbox group for this box, or <code>null</code> 368 * if there is no checkbox group. 369 * @param state The initial state of the checkbox, <code>true</code> for 370 * on, <code>false</code> for off. 371 */ 372public 373Checkbox(String label, CheckboxGroup group, boolean state) 374{ 375 this(label, state, group); 376} 377 378/*************************************************************************/ 379 380/** 381 * Initializes a new instance of <code>Checkbox</code> with the specified 382 * label, initial state, and checkbox group. 383 * 384 * @param label The label for this checkbox. 385 * @param state The initial state of the checkbox, <code>true</code> for 386 * on, <code>false</code> for off. 387 * @param group The checkbox group for this box, or <code>null</code> 388 * if there is no checkbox group. 389 */ 390public 391Checkbox(String label, boolean state, CheckboxGroup group) 392{ 393 this.label = label; 394 this.state = state; 395 this.group = group; 396 397 if ( state && group != null ) 398 { 399 group.setSelectedCheckbox(this); 400 } 401} 402 403/*************************************************************************/ 404 405/* 406 * Instance Variables 407 */ 408 409/** 410 * Returns the label for this checkbox. 411 * 412 * @return The label for this checkbox. 413 */ 414public String 415getLabel() 416{ 417 return(label); 418} 419 420/*************************************************************************/ 421 422/** 423 * Sets the label for this checkbox to the specified value. 424 * 425 * @param label The new checkbox label. 426 */ 427public synchronized void 428setLabel(String label) 429{ 430 this.label = label; 431 if (peer != null) 432 { 433 CheckboxPeer cp = (CheckboxPeer) peer; 434 cp.setLabel(label); 435 } 436} 437 438/*************************************************************************/ 439 440/** 441 * Returns the state of this checkbox. 442 * 443 * @return The state of this checkbox, which will be <code>true</code> for 444 * on and <code>false</code> for off. 445 */ 446public boolean 447getState() 448{ 449 return(state); 450} 451 452/*************************************************************************/ 453 454/** 455 * Sets the state of this checkbox to the specified value. 456 * 457 * @param state The new state of the checkbox, which will be <code>true</code> 458 * for on or <code>false</code> for off. 459 */ 460public synchronized void 461setState(boolean state) 462{ 463 if (this.state != state) 464 { 465 this.state = state; 466 if (peer != null) 467 { 468 CheckboxPeer cp = (CheckboxPeer) peer; 469 cp.setState (state); 470 } 471 } 472} 473 474/*************************************************************************/ 475 476/** 477 * Returns an array of length one containing the checkbox label if this 478 * checkbox is selected. Otherwise <code>null</code> is returned. 479 * 480 * @return The selection state of this checkbox. 481 */ 482public Object[] 483getSelectedObjects() 484{ 485 if (state == false) 486 return(null); 487 488 Object[] objs = new Object[1]; 489 objs[0] = label; 490 491 return(objs); 492} 493 494/*************************************************************************/ 495 496/** 497 * Returns the checkbox group this object is a member of, if any. 498 * 499 * @return This object's checkbox group, of <code>null</code> if it is 500 * not a member of any group. 501 */ 502public CheckboxGroup 503getCheckboxGroup() 504{ 505 return(group); 506} 507 508/*************************************************************************/ 509 510/** 511 * Sets this object's checkbox group to the specified group. 512 * 513 * @param group The new checkbox group, or <code>null</code> to make this 514 * object part of no checkbox group. 515 */ 516public synchronized void 517setCheckboxGroup(CheckboxGroup group) 518{ 519 this.group = group; 520 if (peer != null) 521 { 522 CheckboxPeer cp = (CheckboxPeer) peer; 523 cp.setCheckboxGroup (group); 524 } 525} 526 527/*************************************************************************/ 528 529/** 530 * Creates this object's native peer. 531 */ 532public void 533addNotify() 534{ 535 if (peer == null) 536 peer = getToolkit ().createCheckbox (this); 537 super.addNotify (); 538} 539 540 public ItemListener[] getItemListeners () 541 { 542 return (ItemListener[]) 543 AWTEventMulticaster.getListeners (item_listeners, ItemListener.class); 544 } 545 546/** 547 * Adds a new listeners to the list of registered listeners for this object. 548 * 549 * @param listener The new listener to add. 550 */ 551public synchronized void 552addItemListener(ItemListener listener) 553{ 554 item_listeners = AWTEventMulticaster.add(item_listeners, listener); 555} 556 557/*************************************************************************/ 558 559/** 560 * Removes a listener from the list of registered listeners for this object. 561 * 562 * @param listener The listener to remove. 563 */ 564public synchronized void 565removeItemListener(ItemListener listener) 566{ 567 item_listeners = AWTEventMulticaster.remove(item_listeners, listener); 568} 569 570/*************************************************************************/ 571 572/** 573 * Processes this event by calling <code>processItemEvent()</code> if it 574 * is any instance of <code>ItemEvent</code>. Otherwise it is passed to 575 * the superclass for processing. 576 * 577 * @param event The event to process. 578 */ 579protected void 580processEvent(AWTEvent event) 581{ 582 if (event instanceof ItemEvent) 583 processItemEvent((ItemEvent)event); 584 else 585 super.processEvent(event); 586} 587 588/*************************************************************************/ 589 590/** 591 * Processes this event by dispatching it to any registered listeners. 592 * 593 * @param event The <code>ItemEvent</code> to process. 594 */ 595protected void 596processItemEvent(ItemEvent event) 597{ 598 if (item_listeners != null) 599 item_listeners.itemStateChanged(event); 600} 601 602void 603dispatchEventImpl(AWTEvent e) 604{ 605 if (e.id <= ItemEvent.ITEM_LAST 606 && e.id >= ItemEvent.ITEM_FIRST) 607 { 608 ItemEvent ie = (ItemEvent) e; 609 int itemState = ie.getStateChange(); 610 setState(itemState == ItemEvent.SELECTED ? true : false); 611 if (item_listeners != null 612 || (eventMask & AWTEvent.ITEM_EVENT_MASK) != 0) 613 processEvent(e); 614 } 615 else 616 super.dispatchEventImpl(e); 617} 618 619/*************************************************************************/ 620 621/** 622 * Returns a debugging string for this object. 623 */ 624protected String 625paramString() 626{ 627 // Note: We cannot add the checkbox group information here because this 628 // would trigger infinite recursion when CheckboxGroup.toString() is 629 // called and the box is in its selected state. 630 return ("label=" + label + ",state=" + state + "," + super.paramString()); 631} 632 633/** 634 * Gets the AccessibleContext associated with this <code>Checkbox</code>. 635 * The context is created, if necessary. 636 * 637 * @return the associated context 638 */ 639public AccessibleContext getAccessibleContext() 640{ 641 /* Create the context if this is the first request */ 642 if (accessibleContext == null) 643 { 644 AccessibleAWTCheckbox ac = new AccessibleAWTCheckbox(); 645 accessibleContext = ac; 646 addItemListener(ac); 647 } 648 return accessibleContext; 649} 650 651 /** 652 * Generate a unique name for this checkbox. 653 * 654 * @return A unique name for this checkbox. 655 */ 656 String generateName() 657 { 658 return "checkbox" + getUniqueLong(); 659 } 660 661 private static synchronized long getUniqueLong() 662 { 663 return next_checkbox_number++; 664 } 665}