001 
002 /*
003  *  JScripter Standard 1.0 - To Script In Java
004  *  Copyright (C) 2008-2011  J.J.Liu<jianjunliu@126.com> <http://www.jscripter.org>
005  *  
006  *  This program is free software: you can redistribute it and/or modify
007  *  it under the terms of the GNU Affero General Public License as published by
008  *  the Free Software Foundation, either version 3 of the License, or
009  *  (at your option) any later version.
010  *  
011  *  This program is distributed in the hope that it will be useful,
012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014  *  GNU Affero General Public License for more details.
015  *  
016  *  You should have received a copy of the GNU Affero General Public License
017  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
018  */
019 
020 package jsx.ui.html;
021 
022 import js.Id;
023 import js.Js;
024 import js.user.JsHTMLInputElement;
025 import jsx.core.ArrayLikes;
026 import jsx.ui.Component;
027 import jsx.ui.event.Change;
028 import jsx.ui.event.Check;
029 import jsx.ui.event.Click;
030 import jsx.ui.event.OnClick;
031 import jsx.ui.event.Uncheck;
032 
033 /**
034  * <p>An abstract base class for HTML elementary checkable input widgets.</p>
035  * 
036  * @author <a href="mailto:jianjunliu@126.com">J.J.Liu (Jianjun Liu)</a> at <a href="http://www.jscripter.org" target="_blank">http://www.jscripter.org</a>
037  */
038 public abstract class Choice extends Input implements OnClick
039 {
040     /**
041      * <p>A global identifier for a configurable property of a {@link Choice} widget.</p>
042      * <p>The identified configurable property of a {@link Choice} widget is a reference 
043      * to a {@link Group} object that defines the group that a choice widget belongs to.</p>
044      * @since 1.0
045      */
046     public final static Id<Group> GROUP = new Id<Group>();
047 
048     /**
049      * <p>Typically constructs a choice widget.</p>
050      * @param html The HTML text of the choice widget.
051      * @since 1.0
052      */
053     protected Choice(String html) {
054         super(html);
055         addListener(Click.class, this);
056     }
057 
058     /**
059      * <p>Typically constructs a choice widget in a group.</p>
060      * @param group The group this choice joins.
061      * @param html The HTML text of the choice widget.
062      * @since 1.0
063      */
064     protected Choice(Group group, String html) {
065         this(html);
066         ArrayLikes.add(ini(group).var(Group.CHOICES), this);
067         ini(this).var(GROUP, group);
068     }
069 
070     /**
071      * <p>Checks whether the choice is checked.</p>
072      * @return The "checked" state of the underlying input element.
073      * @since 1.0
074      */
075     public Boolean checked() {
076         return JsHTMLInputElement.checked.with(
077                 Component.getHTMLElement(unwrap())
078         );
079     }
080 
081     /**
082      * <p>Sets "checked" state of the choice.</p>
083      * <p>This method synchronizes the group of choices.</p>
084      * @param checked The new "checked" state for the underlying input element.
085      * @since 1.0
086      */
087     public void setChecked(boolean checked) {
088         Component e = unwrap();
089         JsHTMLInputElement.checked.with(
090                 Component.getHTMLElement(e),
091                 checked
092         );
093         synchronize();
094     }
095 
096     private final static Id<Boolean> CHECKED = new Id<Boolean>();
097 
098     /**
099      * <p>Synchronizes the state of the choice.</p>
100      * <p>This method checks the "checked" state of the underlying input element. It fires
101      * {@link Check}, {@link Uncheck} or {@link Change} event from the choice widget
102      * depending on the "checked" states.</p>
103      * @return <tt>true</tt> if the "checked" state of the underlying input element has been
104      * changed; <tt>false</tt>, otherwise.
105      * @since 1.0
106      */
107     public boolean synchronize() {
108         Boolean checked = checked();
109         boolean changed = Js.not(ini(this).var(CHECKED)) == checked;
110         if (changed) {
111             ini(this).var(CHECKED, checked);
112             Component e = unwrap();
113             fire(new Change(e));
114             if (checked) {
115                 fire(new Check(e));
116             } else {
117                 fire(new Uncheck(e));
118             }
119         }
120         return changed;
121     }
122 
123     /**
124      * <p>Performs an action on the dispatched event.</p>
125      * <p>This method simply invokes {@link #synchronize()} method.</p>
126      * @param evt The event dispatched to this listener.
127      * @since 1.0
128      */
129     public void onEvent(Click evt) {
130         synchronize();
131     }
132 }